Skip to content

Commit

Permalink
Update Update Collection Dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
timoclsn committed Oct 15, 2023
1 parent 3eb708f commit 19aa5cc
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 182 deletions.
30 changes: 18 additions & 12 deletions apps/resources/app/collections/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Button, Heading, Text } from 'design-system';
import { getCollectionCached } from 'lib/cache';
import { SearchParams } from 'lib/types';
import { DeleteCollectionButton } from '../../../components/Collections/DeleteCollectionButton/DeleteCollectionButton';
import { notFound } from 'next/navigation';

interface Props {
params: {
Expand All @@ -21,24 +22,29 @@ const CollectionPage = async ({ params, searchParams }: Props) => {

return (
<>
<div>
<Heading>Collection Page</Heading>
{userId && (
<div className="flex flex-col items-start gap-4">
<UpdateCollectionDialog collectionId={Number(id)}>
<Button>Update Collection</Button>
</UpdateCollectionDialog>
<DeleteCollectionButton collectionId={Number(id)} />
</div>
)}
</div>
<Heading>Collection Page</Heading>
<Await promise={promise}>
{(collection) => {
if (!collection) return <div>No collection found</div>;
if (!collection) {
notFound();
}
const isOwnCollection = collection.user?.id === userId;

return (
<div className="flex flex-col gap-4">
{isOwnCollection && (
<div className="flex flex-col items-start gap-4">
<UpdateCollectionDialog
collectionId={Number(id)}
collectionTitle={collection.title}
collectionDescription={collection.description}
>
<Button>Update Collection</Button>
</UpdateCollectionDialog>
<DeleteCollectionButton collectionId={Number(id)} />
</div>
)}

<div className="flex flex-col gap-2">
<Heading>Title: {collection.title}</Heading>
<Text>Description: {collection.description}</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,148 @@
'use client';

import { cva } from 'class-variance-authority';
import {
AddCollectionSchema,
addCollectionSchema,
} from 'components/Collections/AddCollectionDialog/schemas';
import {
Button,
Dialog,
DialogContent,
DialogOverlay,
DialogPortal,
DialogTrigger,
Heading,
InfoBox,
} from 'design-system';
import { useZodForm } from 'hooks/useZodForm';
import { useAction } from 'lib/serverActions/client';
import { AlertTriangle, Loader2, MessageCircle } from 'lucide-react';
import { ReactNode, useState } from 'react';
import { UpdateCollectionForm } from './UpdateCollectionForm';
import { getData } from './actions';
import { SubmitHandler } from 'react-hook-form';
import { updateCollection } from './actions';

const inputStyles = cva(
'px-8 py-4 text-base text-text-secondary bg-ghost-main-dark-bg outline-none w-full ring-inset',
{
variants: {
error: {
true: 'ring-2 ring-red-700',
false: 'focus-visible:ring-2 focus-visible:ring-ghost-contrast-text',
},
},
},
);

const errorStyles =
'absolute left-0 bottom-0 -mb-4 text-red-700 text-sm slide-in-from-top-full duration-100 ease-in-out fade-in animate-in';

interface Props {
children: ReactNode;
collectionId: number;
collectionTitle: string;
collectionDescription: string;
}

export const UpdateCollectionDialog = ({ children, collectionId }: Props) => {
export const UpdateCollectionDialog = ({
children,
collectionId,
collectionTitle,
collectionDescription,
}: Props) => {
const [open, setOpen] = useState(false);
const { isRunning, data: collection, error, runAction } = useAction(getData);

const isLoading = isRunning && !collection;
const { error, runAction, isRunning } = useAction(updateCollection, {
onSuccess: () => {
setOpen(false);
},
});
const {
register,
handleSubmit,
formState: { errors },
} = useZodForm({
schema: addCollectionSchema,
defaultValues: {
title: collectionTitle,
description: collectionDescription,
},
});

const onSubmit: SubmitHandler<AddCollectionSchema> = async ({
title,
description,
}) => {
await runAction({
collectionId,
title,
description,
});
};

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger
onClick={() => {
runAction({ collectionId });
}}
asChild
>
{children}
</DialogTrigger>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogPortal>
<DialogOverlay />
<DialogContent>
<Heading level="3">Update Collection</Heading>
{isLoading && <div>loading</div>}
{error && <div>{error}</div>}
{collection && (
<UpdateCollectionForm
collectionId={collectionId}
title={collection.title}
description={collection.description}
onSuccess={() => {
setOpen(false);
}}
/>
)}
<form onSubmit={handleSubmit(onSubmit)}>
{/* Title input */}
<div className="relative mb-6 w-full">
<label htmlFor="title" className="sr-only">
Title
</label>
<input
id="title"
placeholder="Title"
type="text"
className={inputStyles({ error: !!errors.title })}
{...register('title')}
/>
{errors.title && (
<p className={errorStyles}>{errors.title.message}</p>
)}
</div>

{/* Description input */}
<div className="relative mb-6 w-full">
<label htmlFor="description" className="sr-only">
Description
</label>
<textarea
id="description"
placeholder="Description"
rows={4}
className={inputStyles({ error: !!errors.description })}
{...register('description')}
/>
{errors.description && (
<p className={errorStyles}>{errors.description.message}</p>
)}
</div>

{/* Submit button */}
<Button type="submit" size="medium" disabled={isRunning}>
{isRunning ? (
<Loader2 className="animate-spin" />
) : (
<MessageCircle />
)}
Update
</Button>

{/* Server messages */}
{error && (
<InfoBox
variant="error"
icon={<AlertTriangle />}
className="animate-in zoom-in-50 fade-in duration-150 ease-in-out"
>
{error}
</InfoBox>
)}
</form>
</DialogContent>
</DialogPortal>
</Dialog>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,33 +1,14 @@
'use server';

import { addCollectionSchema } from 'components/Collections/AddCollectionDialog/schemas';
import { createProtectedAction } from 'lib/serverActions/create';
import {
updateCollection as dbUpdateCollection,
getCollection,
} from 'lib/collections';
import { createProtectedAction } from 'lib/serverActions/create';
import { revalidateTag } from 'next/cache';
import { z } from 'zod';

export const getData = createProtectedAction({
input: z.object({
collectionId: z.number(),
}),
action: async ({ input }) => {
const { collectionId } = input;
const collection = await getCollection(collectionId);

if (!collection) {
throw new Error('Collection not found');
}

return {
title: collection.title,
description: collection.description,
};
},
});

export const updateCollection = createProtectedAction({
input: addCollectionSchema.merge(
z.object({
Expand Down

1 comment on commit 19aa5cc

@vercel
Copy link

@vercel vercel bot commented on 19aa5cc Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.