272 lines
7.6 KiB
TypeScript
Executable File
272 lines
7.6 KiB
TypeScript
Executable File
import {FormImageSelector} from '@common/ui/images/image-selector';
|
|
import {Trans} from '@common/i18n/trans';
|
|
import {FileUploadProvider} from '@common/uploads/uploader/file-upload-provider';
|
|
import {FormTextField} from '@common/ui/forms/input-field/text-field/text-field';
|
|
import {FormSwitch} from '@common/ui/forms/toggle/switch';
|
|
import {FormDatePicker} from '@common/ui/forms/input-field/date/date-picker/date-picker';
|
|
import {FormSelect, Option} from '@common/ui/forms/select/select';
|
|
import {useValueLists} from '@common/http/value-lists';
|
|
import {useForm} from 'react-hook-form';
|
|
import {
|
|
CreateTitlePayload,
|
|
useCreateTitle,
|
|
} from '@app/admin/titles/requests/use-create-title';
|
|
import {Title} from '@app/titles/models/title';
|
|
import {Form} from '@common/ui/forms/form';
|
|
import {useUpdateTitle} from '@app/admin/titles/requests/use-update-title';
|
|
import {toast} from '@common/ui/toast/toast';
|
|
import {message} from '@common/i18n/message';
|
|
import {useNavigate} from '@common/utils/hooks/use-navigate';
|
|
import {useOutletContext} from 'react-router-dom';
|
|
import React, {Fragment} from 'react';
|
|
import {TitleEditorLayout} from '@app/admin/titles/title-editor/title-editor-layout';
|
|
import {Button} from '@common/ui/buttons/button';
|
|
import {useCurrentDateTime} from '@common/i18n/use-current-date-time';
|
|
import {FormComboBox} from '@common/ui/forms/combobox/form-combobox';
|
|
|
|
export function TitlePrimaryFactsForm() {
|
|
const title = useOutletContext<Title>();
|
|
|
|
return (
|
|
<FileUploadProvider>
|
|
{title ? <EditTitleForm title={title} /> : <CreateTitleForm />}
|
|
</FileUploadProvider>
|
|
);
|
|
}
|
|
|
|
function CreateTitleForm() {
|
|
const now = useCurrentDateTime();
|
|
const navigate = useNavigate();
|
|
const form = useForm<CreateTitlePayload>({
|
|
defaultValues: {
|
|
release_date: now.toAbsoluteString(),
|
|
certification: 'pg',
|
|
language: 'en',
|
|
},
|
|
});
|
|
const createTitle = useCreateTitle(form);
|
|
const isDirty = Object.keys(form.formState.dirtyFields).length > 0;
|
|
|
|
return (
|
|
<Form
|
|
form={form}
|
|
onSubmit={values => {
|
|
createTitle.mutate(values, {
|
|
onSuccess: response => {
|
|
toast(message('Title created'));
|
|
navigate(`../${response.title.id}/edit`, {
|
|
relative: 'path',
|
|
replace: true,
|
|
});
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
<TitleEditorLayout
|
|
actions={
|
|
<Button
|
|
variant="flat"
|
|
color="primary"
|
|
type="submit"
|
|
disabled={createTitle.isPending || !isDirty}
|
|
>
|
|
<Trans message="Create" />
|
|
</Button>
|
|
}
|
|
>
|
|
<FormFields />
|
|
</TitleEditorLayout>
|
|
</Form>
|
|
);
|
|
}
|
|
|
|
interface EditTitleFormProps {
|
|
title: Title;
|
|
}
|
|
function EditTitleForm({title}: EditTitleFormProps) {
|
|
const navigate = useNavigate();
|
|
const form = useForm<CreateTitlePayload>({
|
|
defaultValues: {
|
|
name: title.name,
|
|
is_series: title.is_series,
|
|
original_title: title.original_title,
|
|
poster: title.poster,
|
|
backdrop: title.backdrop,
|
|
release_date: title.release_date,
|
|
tagline: title.tagline,
|
|
description: title.description,
|
|
runtime: title.runtime,
|
|
certification: title.certification,
|
|
budget: title.budget,
|
|
revenue: title.revenue,
|
|
language: title.language,
|
|
popularity: title.popularity,
|
|
},
|
|
});
|
|
const updateTitle = useUpdateTitle(form);
|
|
|
|
return (
|
|
<Form
|
|
form={form}
|
|
onSubmit={values => {
|
|
updateTitle.mutate(values, {
|
|
onSuccess: () => {
|
|
toast(message('Title updated'));
|
|
navigate('../../../', {relative: 'path', replace: true});
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
<TitleEditorLayout
|
|
actions={
|
|
<Button
|
|
variant="flat"
|
|
color="primary"
|
|
type="submit"
|
|
disabled={updateTitle.isPending || !form.formState.isDirty}
|
|
>
|
|
<Trans message="Save" />
|
|
</Button>
|
|
}
|
|
>
|
|
<FormFields />
|
|
</TitleEditorLayout>
|
|
</Form>
|
|
);
|
|
}
|
|
|
|
function FormFields() {
|
|
return (
|
|
<Fragment>
|
|
<div className="gap-24 md:flex">
|
|
<FormImageSelector
|
|
variant="square"
|
|
previewSize="w-204 aspect-poster"
|
|
name="poster"
|
|
diskPrefix="title-posters"
|
|
label={<Trans message="Poster" />}
|
|
showRemoveButton
|
|
/>
|
|
<div className="flex-auto max-md:mt-24">
|
|
<FormImageSelector
|
|
name="backdrop"
|
|
variant="square"
|
|
diskPrefix="title-backdrops"
|
|
label={<Trans message="Backdrop" />}
|
|
stretchPreview
|
|
previewSize="min-h-124"
|
|
className="mb-24"
|
|
/>
|
|
<FormTextField
|
|
name="name"
|
|
label={<Trans message="Title" />}
|
|
className="mb-24"
|
|
required
|
|
/>
|
|
<FormTextField
|
|
name="original_title"
|
|
label={<Trans message="Original title" />}
|
|
className="mb-24"
|
|
/>
|
|
<FormSwitch name="is_series" className="mb-24">
|
|
<Trans message="Series" />
|
|
</FormSwitch>
|
|
</div>
|
|
</div>
|
|
<FormDatePicker
|
|
name="release_date"
|
|
label={<Trans message="Release date" />}
|
|
className="mb-24"
|
|
granularity="day"
|
|
/>
|
|
<FormTextField
|
|
name="tagline"
|
|
label={<Trans message="Tagline" />}
|
|
className="mb-24"
|
|
/>
|
|
<FormTextField
|
|
name="description"
|
|
label={<Trans message="Overview" />}
|
|
inputElementType="textarea"
|
|
rows={4}
|
|
className="mb-24"
|
|
/>
|
|
<div className="mb-24 items-center gap-24 md:flex">
|
|
<FormTextField
|
|
name="runtime"
|
|
label={<Trans message="Runtime" />}
|
|
type="number"
|
|
min={1}
|
|
className="flex-1 max-md:mb-24"
|
|
/>
|
|
<CertificationCombobox />
|
|
</div>
|
|
<div className="mb-24 items-center gap-24 md:flex">
|
|
<FormTextField
|
|
name="budget"
|
|
label={<Trans message="Budget (US dollars)" />}
|
|
type="number"
|
|
min={1}
|
|
className="flex-1 max-md:mb-24"
|
|
/>
|
|
<FormTextField
|
|
name="revenue"
|
|
label={<Trans message="Revenue (US dollars)" />}
|
|
type="number"
|
|
min={1}
|
|
className="flex-1 max-md:mb-24"
|
|
/>
|
|
</div>
|
|
<div className="mb-24 items-center gap-24 md:flex">
|
|
<FormTextField
|
|
name="popularity"
|
|
label={<Trans message="Popularity" />}
|
|
type="number"
|
|
min={1}
|
|
className="flex-1 max-md:mb-24"
|
|
/>
|
|
<LanguageSelect />
|
|
</div>
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
function CertificationCombobox() {
|
|
const {data} = useValueLists(['titleFilterAgeRatings']);
|
|
return (
|
|
<FormComboBox
|
|
name="certification"
|
|
selectionMode="single"
|
|
label={<Trans message="Certification" />}
|
|
className="flex-1"
|
|
allowCustomValue
|
|
>
|
|
{data?.titleFilterAgeRatings.map(({name, value}) => (
|
|
<Option key={value} value={value}>
|
|
<Trans message={name} />
|
|
</Option>
|
|
))}
|
|
</FormComboBox>
|
|
);
|
|
}
|
|
|
|
function LanguageSelect() {
|
|
const {data} = useValueLists(['tmdbLanguages']);
|
|
return (
|
|
<FormSelect
|
|
name="language"
|
|
selectionMode="single"
|
|
label={<Trans message="Language" />}
|
|
showSearchField
|
|
searchPlaceholder="Search languages"
|
|
className="flex-1"
|
|
>
|
|
{data?.tmdbLanguages.map(language => (
|
|
<Option key={language.code} value={language.code}>
|
|
<Trans message={language.name} />
|
|
</Option>
|
|
))}
|
|
</FormSelect>
|
|
);
|
|
}
|