126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
import { useState } from 'react';
|
|
import { useForm } from '@inertiajs/react';
|
|
import { FormErrors, controlClass } from '@/components/procurement';
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
type Choice = { value: string; label: string };
|
|
type Props = {
|
|
route: string;
|
|
record: { record_key: string; version: number };
|
|
choices: Choice[];
|
|
today?: string;
|
|
data?: Record<string, string | number | boolean | null>;
|
|
};
|
|
|
|
function Confirm({ props, choice }: { props: Props; choice: Choice }) {
|
|
const form = useForm({
|
|
operation_key: crypto.randomUUID(),
|
|
record_key: props.record.record_key,
|
|
version: props.record.version,
|
|
action: choice.value,
|
|
reason: '',
|
|
data: {
|
|
...props.data,
|
|
...(choice.value === 'execute'
|
|
? { event_on: props.today ?? '', evidence: '' }
|
|
: {}),
|
|
},
|
|
});
|
|
return (
|
|
<form
|
|
className="mt-3 grid gap-3 md:grid-cols-2"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
form.post(props.route);
|
|
}}
|
|
>
|
|
<FormErrors errors={form.errors} />
|
|
<label className="grid gap-1 text-sm">
|
|
Motivo e evidência da conferência
|
|
<textarea
|
|
required
|
|
minLength={10}
|
|
maxLength={4000}
|
|
className={controlClass}
|
|
value={form.data.reason}
|
|
onChange={(e) => form.setData('reason', e.target.value)}
|
|
/>
|
|
</label>
|
|
{choice.value === 'execute' && (
|
|
<>
|
|
<label className="grid gap-1 text-sm">
|
|
Data efectiva do evento
|
|
<input
|
|
type="date"
|
|
required
|
|
max={props.today}
|
|
className={controlClass}
|
|
value={String(form.data.data.event_on ?? '')}
|
|
onChange={(e) =>
|
|
form.setData('data', {
|
|
...form.data.data,
|
|
event_on: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="grid gap-1 text-sm">
|
|
Comprovativo da execução física
|
|
<input
|
|
required
|
|
minLength={10}
|
|
maxLength={3000}
|
|
className={controlClass}
|
|
value={String(form.data.data.evidence ?? '')}
|
|
onChange={(e) =>
|
|
form.setData('data', {
|
|
...form.data.data,
|
|
evidence: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
</>
|
|
)}
|
|
<Button disabled={form.processing}>{choice.label}</Button>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
export function InventoryEventActions(props: Props) {
|
|
const [selected, setSelected] = useState(
|
|
props.choices.length === 1 ? props.choices[0].value : '',
|
|
);
|
|
if (props.choices.length === 0) return null;
|
|
const choice = props.choices.find((option) => option.value === selected);
|
|
return (
|
|
<details className="mt-4">
|
|
<summary className="cursor-pointer text-sm font-medium">
|
|
{props.choices.length === 1
|
|
? props.choices[0].label
|
|
: 'Acções da minha responsabilidade'}
|
|
</summary>
|
|
{props.choices.length > 1 && (
|
|
<label className="mt-3 grid gap-1 text-sm">
|
|
Acção
|
|
<select
|
|
className={controlClass}
|
|
value={selected}
|
|
onChange={(e) => setSelected(e.target.value)}
|
|
>
|
|
<option value="">Seleccione a decisão</option>
|
|
{props.choices.map((option) => (
|
|
<option key={option.value} value={option.value}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)}
|
|
{choice && (
|
|
<Confirm key={choice.value} props={props} choice={choice} />
|
|
)}
|
|
</details>
|
|
);
|
|
}
|