Files
Investidor-V2/resources/js/pages/management/opportunities.tsx
T

255 lines
9.4 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>
);
}