193 lines
5.8 KiB
Dart
193 lines
5.8 KiB
Dart
part of '../../app/app.dart';
|
|
|
|
class ExpertiseForm extends StatelessWidget {
|
|
const ExpertiseForm({
|
|
super.key,
|
|
required this.dlp,
|
|
required this.fields,
|
|
required this.textControllers,
|
|
required this.selectValues,
|
|
required this.multiValues,
|
|
required this.onChanged,
|
|
});
|
|
|
|
final String dlp;
|
|
final List<dynamic> fields;
|
|
final Map<String, TextEditingController> textControllers;
|
|
final Map<String, String> selectValues;
|
|
final Map<String, Set<String>> multiValues;
|
|
final VoidCallback onChanged;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(14),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
_templateTitle(dlp),
|
|
style: Theme.of(
|
|
context,
|
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800),
|
|
),
|
|
const SizedBox(height: 12),
|
|
...fields.map((rawField) => _buildField(context, asMap(rawField))),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildField(BuildContext context, Map<String, dynamic> field) {
|
|
final name = field['name']?.toString() ?? '';
|
|
final label = field['label']?.toString() ?? name;
|
|
final type = field['type']?.toString() ?? 'text';
|
|
final options = asList(
|
|
field['options'],
|
|
).map((item) => item.toString()).toList();
|
|
|
|
if (type == 'select') {
|
|
final currentValue = options.contains(selectValues[name])
|
|
? selectValues[name]
|
|
: null;
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: DropdownButtonFormField<String>(
|
|
initialValue: currentValue,
|
|
isExpanded: true,
|
|
decoration: InputDecoration(
|
|
labelText: label,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
items: options
|
|
.map(
|
|
(option) =>
|
|
DropdownMenuItem(value: option, child: Text(option)),
|
|
)
|
|
.toList(),
|
|
onChanged: (value) {
|
|
selectValues[name] = value ?? '';
|
|
onChanged();
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
if (type == 'multiselect') {
|
|
final selected = multiValues[name] ?? <String>{};
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: InputDecorator(
|
|
decoration: InputDecoration(
|
|
labelText: label,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
child: Wrap(
|
|
spacing: 8,
|
|
runSpacing: 4,
|
|
children: options
|
|
.map(
|
|
(option) => FilterChip(
|
|
label: Text(option),
|
|
selected: selected.contains(option),
|
|
onSelected: (checked) {
|
|
if (checked) {
|
|
selected.add(option);
|
|
} else {
|
|
selected.remove(option);
|
|
}
|
|
multiValues[name] = selected;
|
|
onChanged();
|
|
},
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
final controller = textControllers[name] ??= TextEditingController();
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: TextField(
|
|
controller: controller,
|
|
minLines: type == 'textarea' ? 4 : 1,
|
|
maxLines: type == 'textarea' ? 8 : 1,
|
|
decoration: InputDecoration(
|
|
labelText: label,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class ExpertiseActions extends StatelessWidget {
|
|
const ExpertiseActions({
|
|
super.key,
|
|
required this.isSupervisor,
|
|
required this.saving,
|
|
required this.onSave,
|
|
});
|
|
|
|
final bool isSupervisor;
|
|
final bool saving;
|
|
final ValueChanged<String> onSave;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(14),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
FilledButton.icon(
|
|
onPressed: saving ? null : () => onSave('Draft'),
|
|
icon: saving
|
|
? const SizedBox.square(
|
|
dimension: 18,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: const Icon(Icons.save_outlined),
|
|
label: const Text('Save as Draft'),
|
|
),
|
|
if (isSupervisor) ...[
|
|
OutlinedButton.icon(
|
|
onPressed: saving ? null : () => onSave('preliminary'),
|
|
icon: const Icon(Icons.done_all_outlined),
|
|
label: const Text('Save Preliminary result'),
|
|
),
|
|
OutlinedButton.icon(
|
|
onPressed: saving ? null : () => onSave('verifikasi'),
|
|
icon: const Icon(Icons.verified_outlined),
|
|
label: const Text('Save Final Result'),
|
|
),
|
|
] else ...[
|
|
OutlinedButton.icon(
|
|
onPressed: saving
|
|
? null
|
|
: () => onSave('Permohonan Verifikasi'),
|
|
icon: const Icon(Icons.send_outlined),
|
|
label: const Text('Save and Send To SPV'),
|
|
),
|
|
OutlinedButton.icon(
|
|
onPressed: saving
|
|
? null
|
|
: () => onSave('Permohonan Verifikasi Preliminary'),
|
|
icon: const Icon(Icons.outgoing_mail),
|
|
label: const Text('Kirim SPV Preliminary'),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|