Skip to content

Commit

Permalink
feat(frontend): allow updating metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
IgnisDa committed Dec 24, 2024
1 parent e78bc59 commit 80963a7
Showing 1 changed file with 115 additions and 40 deletions.
155 changes: 115 additions & 40 deletions apps/frontend/app/routes/_dashboard.media.update.$action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ import { Form, useLoaderData } from "@remix-run/react";
import {
CreateCustomMetadataDocument,
MediaLot,
MetadataDetailsDocument,
UpdateCustomMetadataDocument,
} from "@ryot/generated/graphql/backend/graphql";
import { camelCase, changeCase, processSubmission } from "@ryot/ts-utils";
import { IconCalendar, IconPhoto, IconVideo } from "@tabler/icons-react";
import { $path } from "remix-routes";
import invariant from "tiny-invariant";
import { match } from "ts-pattern";
import { z } from "zod";
import { zx } from "zodix";
import { useCoreDetails } from "~/lib/hooks";
Expand All @@ -49,7 +53,19 @@ export type SearchParams = z.infer<typeof searchParamsSchema>;
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const { action } = zx.parseParams(params, { action: z.nativeEnum(Action) });
const query = zx.parseQuery(request, searchParamsSchema);
return { query, action };
const details = await match(action)
.with(Action.Create, () => undefined)
.with(Action.Update, async () => {
invariant(query.id);
const { metadataDetails } = await serverGqlService.authenticatedRequest(
request,
MetadataDetailsDocument,
{ metadataId: query.id },
);
return metadataDetails;
})
.exhaustive();
return { query, action, details };
};

export const meta = (_args: MetaArgs<typeof loader>) => {
Expand All @@ -67,23 +83,40 @@ export const action = async ({ request }: ActionFunctionArgs) => {
? JSON.parse(submission.specifics)
: undefined,
};
input.id = undefined;
input.action = undefined;
input.specifics = undefined;
input.genres = input.genres?.split(",");
input.creators = input.creators?.split(",");
const { createCustomMetadata } = await serverGqlService.authenticatedRequest(
request,
CreateCustomMetadataDocument,
{ input },
);
return redirect($path("/media/item/:id", { id: createCustomMetadata.id }));
const id = await match(submission.action)
.with(Action.Create, async () => {
const { createCustomMetadata } =
await serverGqlService.authenticatedRequest(
request,
CreateCustomMetadataDocument,
{ input },
);
return createCustomMetadata.id;
})
.with(Action.Update, async () => {
invariant(submission.id);
await serverGqlService.authenticatedRequest(
request,
UpdateCustomMetadataDocument,
{ input: { existingMetadataId: submission.id, update: input } },
);
return submission.id;
})
.exhaustive();
return redirect($path("/media/item/:id", { id }));
};

const optionalString = z.string().optional();
const optionalStringArray = z.array(z.string()).optional();

const schema = z.object({
title: z.string(),
id: optionalString,
genres: optionalString,
creators: optionalString,
specifics: optionalString,
Expand All @@ -105,26 +138,56 @@ export default function Page() {
<Container>
<Form method="POST" encType="multipart/form-data">
<input hidden name="action" defaultValue={loaderData.action} />
{loaderData.details ? (
<input hidden name="id" defaultValue={loaderData.details.id} />
) : null}
<Stack>
<Title>Create Media</Title>
<TextInput label="Title" required autoFocus name="title" />
<Title>
{loaderData.details
? `Updating ${loaderData.details.title}`
: "Create Media"}
</Title>
<TextInput
required
autoFocus
name="title"
label="Title"
defaultValue={loaderData.details?.title}
/>
<Group wrap="nowrap">
<Select
required
name="lot"
label="Type"
defaultValue={loaderData.query.lot}
defaultValue={loaderData.details?.lot || loaderData.query.lot}
data={Object.values(MediaLot).map((v) => ({
value: v,
label: changeCase(v),
}))}
/>
<Switch mt="md" label="Is it NSFW?" name="isNsfw" />
<Switch
mt="md"
name="isNsfw"
label="Is it NSFW?"
defaultChecked={loaderData.details?.isNsfw || undefined}
/>
</Group>
<JsonInput
label="Specifics"
formatOnBlur
name="specifics"
label="Specifics"
defaultValue={JSON.stringify(
loaderData.details?.movieSpecifics ||
loaderData.details?.showSpecifics ||
loaderData.details?.mangaSpecifics ||
loaderData.details?.animeSpecifics ||
loaderData.details?.podcastSpecifics ||
loaderData.details?.bookSpecifics ||
loaderData.details?.audioBookSpecifics ||
loaderData.details?.visualNovelSpecifics ||
loaderData.details?.videoGameSpecifics ||
loaderData.details?.musicSpecifics,
)}
description={
<>
Please search for <Code>Specifics</Code> inputs at the{" "}
Expand All @@ -137,47 +200,59 @@ export default function Page() {
/>
<Textarea
label="Description"
description="Markdown is supported"
name="description"
description="Markdown is supported"
defaultValue={loaderData.details?.description || undefined}
/>
<FileInput
label="Images"
name="images"
multiple
disabled={fileUploadNotAllowed}
description={
fileUploadNotAllowed &&
"Please set the S3 variables required to enable file uploading"
}
accept="image/png,image/jpeg,image/jpg"
leftSection={<IconPhoto />}
/>
<FileInput
label="Videos"
name="videos"
multiple
disabled={fileUploadNotAllowed}
description={
fileUploadNotAllowed &&
"Please set the S3 variables required to enable file uploading"
}
accept="video/mp4,video/x-m4v,video/*"
leftSection={<IconVideo />}
/>
{!fileUploadNotAllowed ? (
<FileInput
multiple
name="images"
label="Images"
leftSection={<IconPhoto />}
accept="image/png,image/jpeg,image/jpg"
description={
loaderData.details &&
"Please re-upload the images while updating the metadata, old ones will be deleted"
}
/>
) : null}
{!fileUploadNotAllowed ? (
<FileInput
multiple
name="videos"
label="Videos"
leftSection={<IconVideo />}
accept="video/mp4,video/x-m4v,video/*"
description={
loaderData.details &&
"Please re-upload the videos while updating the metadata, old ones will be deleted"
}
/>
) : null}
<NumberInput
name="publishYear"
label="Publish year"
leftSection={<IconCalendar />}
name="publishYear"
defaultValue={loaderData.details?.publishYear || undefined}
/>
<TextInput
name="creators"
label="Creators"
placeholder="Comma separated names"
name="creators"
defaultValue={loaderData.details?.creators
.flatMap((c) => c.items)
.map((c) => c.name)
.join(", ")}
/>
<TextInput
name="genres"
label="Genres"
placeholder="Comma separated values"
name="genres"
defaultValue={
loaderData.details?.genres.map((g) => g.name).join(", ") ||
undefined
}
/>
<Button type="submit">Create</Button>
</Stack>
Expand Down

0 comments on commit 80963a7

Please sign in to comment.