Sender Invitation
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class InvitationFormActions extends StatelessWidget {
|
||||
final int expiryDays;
|
||||
final ValueChanged<int> onExpiryChanged;
|
||||
final bool canCreate;
|
||||
final bool hasRoles;
|
||||
final VoidCallback onSubmit;
|
||||
|
||||
const InvitationFormActions({
|
||||
super.key,
|
||||
required this.expiryDays,
|
||||
required this.onExpiryChanged,
|
||||
required this.canCreate,
|
||||
required this.hasRoles,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
return Row(
|
||||
children: [
|
||||
Text(loc.invitationExpiresIn(expiryDays)),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
label: '$expiryDays',
|
||||
min: 1,
|
||||
max: 30,
|
||||
value: expiryDays.toDouble(),
|
||||
onChanged: (value) => onExpiryChanged(value.round()),
|
||||
),
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: canCreate && hasRoles ? onSubmit : null,
|
||||
icon: const Icon(Icons.send_outlined),
|
||||
label: Text(loc.invitationSendButton),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
89
frontend/pweb/lib/pages/invitations/widgets/form/fields.dart
Normal file
89
frontend/pweb/lib/pages/invitations/widgets/form/fields.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/permissions/descriptions/role.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class InvitationFormFields extends StatelessWidget {
|
||||
final List<RoleDescription> roles;
|
||||
final TextEditingController emailController;
|
||||
final TextEditingController nameController;
|
||||
final TextEditingController messageController;
|
||||
final String? selectedRoleRef;
|
||||
final ValueChanged<String?> onRoleChanged;
|
||||
|
||||
const InvitationFormFields({
|
||||
super.key,
|
||||
required this.roles,
|
||||
required this.emailController,
|
||||
required this.nameController,
|
||||
required this.messageController,
|
||||
required this.selectedRoleRef,
|
||||
required this.onRoleChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
return Column(
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 320,
|
||||
child: TextFormField(
|
||||
controller: emailController,
|
||||
decoration: InputDecoration(
|
||||
labelText: loc.invitationEmailLabel,
|
||||
prefixIcon: const Icon(Icons.alternate_email_outlined),
|
||||
),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: (value) => (value == null || value.trim().isEmpty)
|
||||
? loc.errorEmailMissing
|
||||
: null,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 280,
|
||||
child: TextFormField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: loc.invitationNameLabel,
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 260,
|
||||
child: DropdownButtonFormField<String>(
|
||||
initialValue: selectedRoleRef ?? (roles.isNotEmpty ? roles.first.storable.id : null),
|
||||
items: roles.map((role) => DropdownMenuItem(
|
||||
value: role.storable.id,
|
||||
child: Text(role.describable.name),
|
||||
)).toList(),
|
||||
onChanged: roles.isEmpty ? null : onRoleChanged,
|
||||
decoration: InputDecoration(
|
||||
labelText: loc.invitationRoleLabel,
|
||||
prefixIcon: const Icon(Icons.security_outlined),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: messageController,
|
||||
minLines: 2,
|
||||
maxLines: 3,
|
||||
decoration: InputDecoration(
|
||||
labelText: loc.invitationMessageLabel,
|
||||
prefixIcon: const Icon(Icons.chat_bubble_outline),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
45
frontend/pweb/lib/pages/invitations/widgets/form/form.dart
Normal file
45
frontend/pweb/lib/pages/invitations/widgets/form/form.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/pages/invitations/widgets/form/view.dart';
|
||||
|
||||
|
||||
class InvitationsForm extends StatelessWidget {
|
||||
final GlobalKey<FormState> formKey;
|
||||
final TextEditingController emailController;
|
||||
final TextEditingController nameController;
|
||||
final TextEditingController messageController;
|
||||
final int expiryDays;
|
||||
final ValueChanged<int> onExpiryChanged;
|
||||
final String? selectedRoleRef;
|
||||
final ValueChanged<String?> onRoleChanged;
|
||||
final bool canCreate;
|
||||
final VoidCallback onSubmit;
|
||||
|
||||
const InvitationsForm({
|
||||
super.key,
|
||||
required this.formKey,
|
||||
required this.emailController,
|
||||
required this.nameController,
|
||||
required this.messageController,
|
||||
required this.expiryDays,
|
||||
required this.onExpiryChanged,
|
||||
required this.selectedRoleRef,
|
||||
required this.onRoleChanged,
|
||||
required this.canCreate,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => InvitationFormView(
|
||||
formKey: formKey,
|
||||
emailController: emailController,
|
||||
nameController: nameController,
|
||||
messageController: messageController,
|
||||
expiryDays: expiryDays,
|
||||
onExpiryChanged: onExpiryChanged,
|
||||
selectedRoleRef: selectedRoleRef,
|
||||
onRoleChanged: onRoleChanged,
|
||||
canCreate: canCreate,
|
||||
onSubmit: onSubmit,
|
||||
);
|
||||
}
|
||||
83
frontend/pweb/lib/pages/invitations/widgets/form/view.dart
Normal file
83
frontend/pweb/lib/pages/invitations/widgets/form/view.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/provider/permissions.dart';
|
||||
|
||||
import 'package:pweb/pages/invitations/widgets/form/actions.dart';
|
||||
import 'package:pweb/pages/invitations/widgets/form/fields.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class InvitationFormView extends StatelessWidget {
|
||||
final GlobalKey<FormState> formKey;
|
||||
final TextEditingController emailController;
|
||||
final TextEditingController nameController;
|
||||
final TextEditingController messageController;
|
||||
final int expiryDays;
|
||||
final ValueChanged<int> onExpiryChanged;
|
||||
final String? selectedRoleRef;
|
||||
final ValueChanged<String?> onRoleChanged;
|
||||
final bool canCreate;
|
||||
final VoidCallback onSubmit;
|
||||
|
||||
const InvitationFormView({
|
||||
super.key,
|
||||
required this.formKey,
|
||||
required this.emailController,
|
||||
required this.nameController,
|
||||
required this.messageController,
|
||||
required this.expiryDays,
|
||||
required this.onExpiryChanged,
|
||||
required this.selectedRoleRef,
|
||||
required this.onRoleChanged,
|
||||
required this.canCreate,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
final roles = context.watch<PermissionsProvider>().roleDescriptions;
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: theme.colorScheme.surfaceContainerHighest.withAlpha(40),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
loc.invitationCreateTitle,
|
||||
style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
InvitationFormFields(
|
||||
roles: roles,
|
||||
emailController: emailController,
|
||||
nameController: nameController,
|
||||
messageController: messageController,
|
||||
selectedRoleRef: selectedRoleRef,
|
||||
onRoleChanged: onRoleChanged,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
InvitationFormActions(
|
||||
expiryDays: expiryDays,
|
||||
onExpiryChanged: onExpiryChanged,
|
||||
canCreate: canCreate,
|
||||
hasRoles: roles.isNotEmpty,
|
||||
onSubmit: onSubmit,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user