218 lines
8.8 KiB
TypeScript
218 lines
8.8 KiB
TypeScript
import { Head, Link, router, useForm } from '@inertiajs/react';
|
|
import { FormErrors, controlClass } from '@/components/procurement';
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
type Data = {
|
|
name: string;
|
|
phone: string | null;
|
|
summary: string;
|
|
availability: { province: string; district: string; locality: string };
|
|
};
|
|
export default function Profile({
|
|
companyId,
|
|
email,
|
|
profile,
|
|
emailVerified = false,
|
|
emailDeliveryAvailable = false,
|
|
accessStatus,
|
|
opportunities = [],
|
|
submissions = [],
|
|
}: {
|
|
companyId: number;
|
|
email: string;
|
|
profile: { version: number; data: Data };
|
|
emailVerified?: boolean;
|
|
emailDeliveryAvailable?: boolean;
|
|
accessStatus?: string | null;
|
|
opportunities?: { id: number; title: string; closes_on: string }[];
|
|
submissions?: { id: number; reference: string; created_at: string }[];
|
|
}) {
|
|
const form = useForm({
|
|
version: profile.version,
|
|
...profile.data,
|
|
phone: profile.data.phone ?? '',
|
|
reason: '',
|
|
});
|
|
return (
|
|
<>
|
|
<Head title="O meu perfil" />
|
|
<section className="mx-auto max-w-3xl space-y-3 p-6">
|
|
<h2 className="text-xl font-semibold">
|
|
Oportunidades publicadas
|
|
</h2>
|
|
{opportunities.map((item) => (
|
|
<p key={item.id}>
|
|
<Link
|
|
className="underline"
|
|
href={`/candidaturas/${companyId}/oportunidades/${item.id}`}
|
|
>
|
|
{item.title} · {item.closes_on}
|
|
</Link>
|
|
</p>
|
|
))}
|
|
<h2 className="text-xl font-semibold">
|
|
As minhas candidaturas
|
|
</h2>
|
|
{submissions.map((item) => (
|
|
<p key={item.id}>
|
|
<Link
|
|
className="underline"
|
|
href={`/candidaturas/${companyId}/submissoes/${item.id}`}
|
|
>
|
|
{item.reference} · {item.created_at}
|
|
</Link>
|
|
</p>
|
|
))}
|
|
</section>
|
|
<main className="mx-auto max-w-3xl space-y-6 p-6">
|
|
<p>SGC · Área do candidato</p>
|
|
<h1 className="text-3xl font-semibold">O meu perfil</h1>
|
|
<p>
|
|
{email} · versão {profile.version}
|
|
</p>
|
|
<p>
|
|
{emailVerified
|
|
? 'Email confirmado. A identidade ainda depende de verificação própria.'
|
|
: 'Email ainda não confirmado. A entrada comprova apenas o acesso à conta.'}{' '}
|
|
Pode candidatar-se às oportunidades publicadas. O envio de
|
|
anexos ainda está em desenvolvimento.
|
|
</p>
|
|
{!emailVerified && (
|
|
<Button
|
|
variant="outline"
|
|
disabled={!emailDeliveryAvailable}
|
|
onClick={() =>
|
|
router.post(
|
|
`/candidaturas/${companyId}/pedir-confirmacao`,
|
|
)
|
|
}
|
|
>
|
|
Pedir confirmação do email
|
|
</Button>
|
|
)}
|
|
{!emailVerified && !emailDeliveryAvailable && (
|
|
<p>
|
|
O envio de email ainda não está configurado; pode
|
|
continuar a preparar o perfil.
|
|
</p>
|
|
)}
|
|
{accessStatus === 'requested' && (
|
|
<p>
|
|
Se o envio estiver disponível, receberá uma ligação
|
|
temporária de confirmação.
|
|
</p>
|
|
)}
|
|
<form
|
|
className="space-y-4"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
form.post(`/candidaturas/${companyId}/perfil`, {
|
|
preserveScroll: true,
|
|
preserveState: false,
|
|
});
|
|
}}
|
|
>
|
|
<FormErrors errors={form.errors} />
|
|
<label className="grid gap-2">
|
|
Nome completo
|
|
<input
|
|
className={controlClass}
|
|
required
|
|
minLength={3}
|
|
maxLength={200}
|
|
value={form.data.name}
|
|
onChange={(e) =>
|
|
form.setData('name', e.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="grid gap-2">
|
|
Telefone
|
|
<input
|
|
className={controlClass}
|
|
maxLength={50}
|
|
value={form.data.phone}
|
|
onChange={(e) =>
|
|
form.setData('phone', e.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="grid gap-2">
|
|
Resumo profissional
|
|
<textarea
|
|
className={controlClass}
|
|
required
|
|
minLength={10}
|
|
maxLength={5000}
|
|
value={form.data.summary}
|
|
onChange={(e) =>
|
|
form.setData('summary', e.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<fieldset className="grid gap-3 sm:grid-cols-3">
|
|
<legend>
|
|
Local de disponibilidade para trabalhar ou prestar
|
|
serviço
|
|
</legend>
|
|
{(['province', 'district', 'locality'] as const).map(
|
|
(key) => (
|
|
<label className="grid gap-2" key={key}>
|
|
{
|
|
{
|
|
province: 'Província',
|
|
district: 'Distrito',
|
|
locality: 'Localidade',
|
|
}[key]
|
|
}
|
|
<input
|
|
className={controlClass}
|
|
required
|
|
maxLength={150}
|
|
value={form.data.availability[key]}
|
|
onChange={(e) =>
|
|
form.setData('availability', {
|
|
...form.data.availability,
|
|
[key]: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
),
|
|
)}
|
|
</fieldset>
|
|
<p className="text-sm">
|
|
Disponibilidade é distinta da morada. Actualizar o
|
|
perfil cria uma versão para usos futuros, preservando as
|
|
anteriores.
|
|
</p>
|
|
<label className="grid gap-2">
|
|
Motivo da actualização
|
|
<textarea
|
|
className={controlClass}
|
|
required
|
|
minLength={10}
|
|
maxLength={4000}
|
|
value={form.data.reason}
|
|
onChange={(e) =>
|
|
form.setData('reason', e.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<Button disabled={form.processing}>
|
|
Guardar nova versão do perfil
|
|
</Button>
|
|
</form>
|
|
<Button
|
|
variant="outline"
|
|
onClick={() =>
|
|
router.post(`/candidaturas/${companyId}/sair`)
|
|
}
|
|
>
|
|
Sair da área do candidato
|
|
</Button>
|
|
</main>
|
|
</>
|
|
);
|
|
}
|