157 lines
4.6 KiB
TypeScript
Executable File
157 lines
4.6 KiB
TypeScript
Executable File
import {ColumnConfig} from '@common/datatable/column-config';
|
|
import {PersonCredit, TitleCredit} from '@app/titles/models/title';
|
|
import {Trans} from '@common/i18n/trans';
|
|
import React, {Fragment, useContext, useMemo} from 'react';
|
|
import {Table, TableBodyProps} from '@common/ui/tables/table';
|
|
import {TableRow} from '@common/ui/tables/table-row';
|
|
import {TableContext} from '@common/ui/tables/table-context';
|
|
import {TitlePoster} from '@app/titles/title-poster/title-poster';
|
|
import {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';
|
|
import {IconButton} from '@common/ui/buttons/icon-button';
|
|
import {DeleteIcon} from '@common/icons/material/Delete';
|
|
import {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';
|
|
import {useOutletContext} from 'react-router-dom';
|
|
import {GetPersonResponse} from '@app/people/requests/use-person';
|
|
import {IllustratedMessage} from '@common/ui/images/illustrated-message';
|
|
import {RecentActorsIcon} from '@common/icons/material/RecentActors';
|
|
import {TitleLink} from '@app/titles/title-link';
|
|
import {useDeletePersonCredit} from '@app/admin/people/requests/use-delete-person-credit';
|
|
|
|
const columnConfig: ColumnConfig<PersonCredit>[] = [
|
|
{
|
|
key: 'name',
|
|
header: () => <Trans message="Credit" />,
|
|
visibleInMode: 'all',
|
|
width: 'flex-3',
|
|
body: credit => (
|
|
<div className="flex items-center gap-12">
|
|
<TitlePoster title={credit} srcSize="sm" size="w-32" />
|
|
<div className="overflow-hidden min-w-0">
|
|
<div className="overflow-hidden overflow-ellipsis">
|
|
<TitleLink title={credit} target="_blank" />
|
|
</div>
|
|
<div className="text-muted text-xs overflow-hidden overflow-ellipsis">
|
|
{credit.is_series ? (
|
|
<Trans message="Series" />
|
|
) : (
|
|
<Trans message="Movie" />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: 'year',
|
|
header: () => <Trans message="Year" />,
|
|
body: credit => credit.year,
|
|
},
|
|
{
|
|
key: 'character',
|
|
header: () => <Trans message="Character" />,
|
|
body: credit => (credit.pivot.character ? credit.pivot.character : '-'),
|
|
},
|
|
{
|
|
key: 'department',
|
|
header: () => <Trans message="Department" />,
|
|
body: credit => (
|
|
<span className="capitalize">{credit.pivot.department}</span>
|
|
),
|
|
},
|
|
{
|
|
key: 'job',
|
|
header: () => <Trans message="Job" />,
|
|
body: credit => <span className="capitalize">{credit.pivot.job}</span>,
|
|
},
|
|
{
|
|
key: 'actions',
|
|
header: () => <Trans message="Actions" />,
|
|
hideHeader: true,
|
|
align: 'end',
|
|
width: 'w-42 flex-shrink-0',
|
|
visibleInMode: 'all',
|
|
body: item => (
|
|
<div className="text-muted">
|
|
<DeleteButton credit={item} />
|
|
</div>
|
|
),
|
|
},
|
|
];
|
|
|
|
export function PersonCreditsEditor() {
|
|
const data = useOutletContext<GetPersonResponse>();
|
|
const credits = useMemo(() => {
|
|
return Object.values(data.credits)
|
|
.flat()
|
|
.filter(credit => credit.pivot != null);
|
|
}, [data.credits]);
|
|
return (
|
|
<Fragment>
|
|
<Table
|
|
enableSelection={false}
|
|
columns={columnConfig}
|
|
data={credits}
|
|
cellHeight="h-54"
|
|
tableBody={<CreditsTableBody />}
|
|
/>
|
|
{!credits.length && <NoCreditsMessage />}
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
function CreditsTableBody({renderRowAs}: TableBodyProps) {
|
|
const {data} = useContext(TableContext);
|
|
return (
|
|
<Fragment>
|
|
{data.map((item, rowIndex) => (
|
|
<TableRow
|
|
item={item}
|
|
index={rowIndex}
|
|
// use pivot id for key because some person might
|
|
// appear multiple times with different department
|
|
key={(item as TitleCredit).pivot.id}
|
|
renderAs={renderRowAs}
|
|
/>
|
|
))}
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
function NoCreditsMessage() {
|
|
return (
|
|
<IllustratedMessage
|
|
className="mt-40"
|
|
imageMargin="mb-8"
|
|
image={
|
|
<div className="text-muted">
|
|
<RecentActorsIcon size="xl" />
|
|
</div>
|
|
}
|
|
imageHeight="h-auto"
|
|
title={<Trans message="No credits have been added yet" />}
|
|
/>
|
|
);
|
|
}
|
|
|
|
interface DeleteButtonProps {
|
|
credit: PersonCredit;
|
|
}
|
|
function DeleteButton({credit}: DeleteButtonProps) {
|
|
const deleteCredit = useDeletePersonCredit(credit);
|
|
return (
|
|
<DialogTrigger type="modal">
|
|
<IconButton>
|
|
<DeleteIcon />
|
|
</IconButton>
|
|
<ConfirmationDialog
|
|
isDanger
|
|
title={<Trans message="Delete credit" />}
|
|
body={<Trans message="Are you sure you want to delete this credit?" />}
|
|
confirm={<Trans message="Delete" />}
|
|
isLoading={deleteCredit.isPending}
|
|
onConfirm={() => deleteCredit.mutate()}
|
|
/>
|
|
</DialogTrigger>
|
|
);
|
|
}
|