261 lines
9.6 KiB
TypeScript
261 lines
9.6 KiB
TypeScript
import { Link, useForm } from '@inertiajs/react';
|
|
import {
|
|
Management,
|
|
Pagination,
|
|
button,
|
|
control,
|
|
states,
|
|
type Paginated,
|
|
} from './shared';
|
|
|
|
type Entry = {
|
|
id: number;
|
|
reference: string;
|
|
title: string | null;
|
|
status: string;
|
|
opportunity_category: string | null;
|
|
updated_at: string;
|
|
deleted_at: string | null;
|
|
can_edit?: boolean;
|
|
can_promote?: boolean;
|
|
working_status?: string;
|
|
draft_title?: string;
|
|
publication?: { scope: string; label: string; public_catalog: boolean };
|
|
};
|
|
export default function Opportunities({
|
|
records,
|
|
filters,
|
|
counts,
|
|
categories,
|
|
sectors,
|
|
geographyReviewCount,
|
|
basePath = '/management/opportunities',
|
|
canCreate = true,
|
|
}: {
|
|
records: Paginated<Entry>;
|
|
filters: {
|
|
q?: string;
|
|
queue?: string;
|
|
status?: string;
|
|
category?: string;
|
|
deleted?: boolean;
|
|
sector_id?: string;
|
|
geography_scope?: string;
|
|
};
|
|
counts: Record<string, number>;
|
|
categories: string[];
|
|
sectors: { id: number; name: string }[];
|
|
geographyReviewCount: number;
|
|
basePath?: string;
|
|
canCreate?: boolean;
|
|
}) {
|
|
const form = useForm({
|
|
q: filters.q ?? '',
|
|
queue: filters.queue ?? '',
|
|
status: filters.status ?? '',
|
|
category: filters.category ?? '',
|
|
deleted: Boolean(filters.deleted),
|
|
sector_id: String(filters.sector_id ?? ''),
|
|
geography_scope: filters.geography_scope ?? '',
|
|
});
|
|
return (
|
|
<Management
|
|
title={
|
|
basePath === '/minhas-oportunidades'
|
|
? 'Minhas oportunidades'
|
|
: 'Gestão de Oportunidades'
|
|
}
|
|
>
|
|
{canCreate && (
|
|
<Link className={button} href={`${basePath}/create`}>
|
|
Nova oportunidade
|
|
</Link>
|
|
)}
|
|
<p>
|
|
{geographyReviewCount} registos com âmbito por indicar;
|
|
referências existentes permanecem aceites.
|
|
</p>
|
|
<section
|
|
aria-label="Indicadores autorizados"
|
|
className="grid gap-3 sm:grid-cols-3"
|
|
>
|
|
{[
|
|
'draft',
|
|
'submitted',
|
|
'needs_information',
|
|
'in_review',
|
|
'information_pending',
|
|
'returned',
|
|
'approved',
|
|
'published',
|
|
'suspended',
|
|
'rejected',
|
|
'archived',
|
|
].map((s) => (
|
|
<Link
|
|
className="rounded border p-3"
|
|
key={s}
|
|
href={`${basePath}?status=${s}`}
|
|
>
|
|
{states[s] ?? s}: {counts[s] ?? 0}
|
|
</Link>
|
|
))}
|
|
</section>
|
|
<form
|
|
className="flex flex-wrap gap-3"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
form.transform((data) => ({
|
|
...data,
|
|
deleted: data.deleted ? '1' : '0',
|
|
}));
|
|
form.get(basePath);
|
|
}}
|
|
>
|
|
{basePath === '/minhas-oportunidades' && (
|
|
<label>
|
|
Fila
|
|
<select
|
|
className={control}
|
|
value={form.data.queue}
|
|
onChange={(e) =>
|
|
form.setData('queue', e.target.value)
|
|
}
|
|
>
|
|
<option value="">Todas as autorizadas</option>
|
|
<option value="assigned">Atribuídas a mim</option>
|
|
<option value="review">
|
|
Validação e pareceres
|
|
</option>
|
|
<option value="publication">
|
|
Preparação editorial
|
|
</option>
|
|
<option value="appeal">Recursos pendentes</option>
|
|
</select>
|
|
</label>
|
|
)}
|
|
<input
|
|
aria-label="Pesquisa global"
|
|
placeholder="Título ou referência"
|
|
className={control}
|
|
value={form.data.q}
|
|
onChange={(e) => form.setData('q', e.target.value)}
|
|
/>
|
|
<select
|
|
aria-label="Estado"
|
|
className={control}
|
|
value={form.data.status}
|
|
onChange={(e) => form.setData('status', e.target.value)}
|
|
>
|
|
<option value="">Todos os estados</option>
|
|
{Object.keys(counts).map((s) => (
|
|
<option key={s} value={s}>
|
|
{states[s] ?? s}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<select
|
|
aria-label="Categoria"
|
|
className={control}
|
|
value={form.data.category}
|
|
onChange={(e) => form.setData('category', e.target.value)}
|
|
>
|
|
<option value="">Todas as categorias</option>
|
|
{categories.map((s) => (
|
|
<option key={s}>{s}</option>
|
|
))}
|
|
</select>
|
|
<label>
|
|
<input
|
|
type="checkbox"
|
|
checked={form.data.deleted}
|
|
onChange={(e) =>
|
|
form.setData('deleted', e.target.checked)
|
|
}
|
|
/>{' '}
|
|
Rascunhos eliminados logicamente
|
|
</label>
|
|
<select
|
|
aria-label="Sector"
|
|
className={control}
|
|
value={form.data.sector_id}
|
|
onChange={(e) => form.setData('sector_id', e.target.value)}
|
|
>
|
|
<option value="">Todos os sectores</option>
|
|
{sectors.map((s) => (
|
|
<option key={s.id} value={s.id}>
|
|
{s.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<select
|
|
aria-label="Âmbito geográfico"
|
|
className={control}
|
|
value={form.data.geography_scope}
|
|
onChange={(e) =>
|
|
form.setData('geography_scope', e.target.value)
|
|
}
|
|
>
|
|
<option value="">Todos os âmbitos</option>
|
|
{[
|
|
'unspecified',
|
|
'specific',
|
|
'multiple',
|
|
'national',
|
|
'digital',
|
|
].map((s) => (
|
|
<option key={s}>{s}</option>
|
|
))}
|
|
</select>
|
|
<button className={button} disabled={form.processing}>
|
|
Pesquisar
|
|
</button>
|
|
</form>
|
|
<div className="space-y-3">
|
|
{records.data.map((r) => (
|
|
<article key={r.id} className="rounded border p-4">
|
|
<h2 className="font-semibold">
|
|
{r.draft_title ?? r.title ?? 'Rascunho sem título'}
|
|
</h2>
|
|
<p>
|
|
ID {r.id} · {r.reference} ·{' '}
|
|
{r.opportunity_category ?? 'Categoria por indicar'}{' '}
|
|
·{' '}
|
|
{r.deleted_at
|
|
? 'Eliminado logicamente'
|
|
: (r.working_status ?? r.status) === 'published'
|
|
? 'Versão disponibilizada'
|
|
: (states[r.working_status ?? r.status] ??
|
|
r.working_status ??
|
|
r.status)}
|
|
</p>
|
|
{r.publication && <p>{r.publication.label}</p>}
|
|
<p>Atualizado: {r.updated_at}</p>
|
|
<div className="flex flex-wrap gap-4">
|
|
<Link href={`${basePath}/${r.id}/view`}>Ver</Link>
|
|
{r.can_promote && (
|
|
<Link
|
|
href={`/minhas-oportunidades/${r.id}/divulgacao`}
|
|
>
|
|
Divulgação promocional
|
|
</Link>
|
|
)}
|
|
{r.can_edit !== false && (
|
|
<Link href={`${basePath}/${r.id}/edit`}>
|
|
{r.deleted_at || r.status === 'archived'
|
|
? 'Restaurar'
|
|
: r.status === 'draft'
|
|
? 'Continuar preenchimento'
|
|
: 'Editar nova versão'}
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</article>
|
|
))}
|
|
</div>
|
|
{!records.data.length && <p>Nenhum registo encontrado.</p>}
|
|
<Pagination page={records} />
|
|
</Management>
|
|
);
|
|
}
|