Skip to content

Commit

Permalink
feat(core): add wishlist drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
yurytut1993 committed Jul 29, 2024
1 parent 868e1ba commit b7c28f0
Show file tree
Hide file tree
Showing 25 changed files with 1,358 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .changeset/odd-oranges-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

add wishlist book
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use server';

import { revalidatePath } from 'next/cache';

import {
deleteWishlists as deleteWishlistsClient,
Input,
} from '~/client/mutations/delete-wishlists';

export const deleteWishlists = async (wishlists: Input) => {
try {
const result = await deleteWishlistsClient(wishlists);

revalidatePath('/account/wishlists', 'page');

if (result === 'success') {
return {
status: 'success',
};
}
} catch (error: unknown) {
if (error instanceof Error) {
return {
status: 'error',
message: error.message,
};
}
}

return { status: 'error', message: 'Unknown error.' };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use server';

import { revalidatePath } from 'next/cache';
import { z } from 'zod';

import { createWishlist as createWishlistClient } from '~/client/mutations/create-wishlist';

const CreateWishlistSchema = z.object({
name: z.string(),
});

export const createWishlist = async (formData: FormData) => {
const parsedData = CreateWishlistSchema.parse({
name: formData.get('name'),
});

const input = {
...parsedData,
isPublic: true,
};

try {
const newWishlist = await createWishlistClient({ input });

revalidatePath('/account/wishlists', 'page');

if (newWishlist) {
return {
status: 'success',
data: newWishlist,
};
}
} catch (error: unknown) {
if (error instanceof Error) {
return {
status: 'error',
message: error.message,
};
}
}

return { status: 'error', message: 'Unknown error.' };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useTranslations } from 'next-intl';
import { ChangeEvent, useState } from 'react';
import { useFormStatus } from 'react-dom';

import { createWishlist as createWishlistMutation } from '~/client/mutations/create-wishlist';
import { Button } from '~/components/ui/button';
import { DialogCancel } from '~/components/ui/dialog';
import {
Field,
FieldControl,
FieldLabel,
FieldMessage,
Form,
FormSubmit,
} from '~/components/ui/form';
import { Input } from '~/components/ui/input';

import { Wishlists } from '..';
import { useAccountStatusContext } from '../../account-status-provider';

import { createWishlist } from './_actions/create-wishlist';

type Wishlist = NonNullable<Awaited<ReturnType<typeof createWishlistMutation>>>;

interface Props {
onWishlistCreated: (newWishlist: Wishlists[number] & Wishlist) => void;
}

const SubmitButton = () => {
const { pending } = useFormStatus();
const t = useTranslations('Account.Wishlist');

return (
<FormSubmit asChild>
<Button
className="relative w-fit items-center px-8 py-2"
loading={pending}
loadingText={t('onSubmitText')}
variant="primary"
>
{t('submitFormText')}
</Button>
</FormSubmit>
);
};

export const CreateWishlistForm = ({ onWishlistCreated }: Props) => {
const [isInputValid, setInputValidation] = useState(true);
const { setAccountState } = useAccountStatusContext();

const t = useTranslations('Account.Wishlist');

const handleInputValidation = (e: ChangeEvent<HTMLInputElement>) => {
const validationStatus = e.target.validity.valueMissing;

setInputValidation(!validationStatus);
};

const onSubmit = async (formData: FormData) => {
const submit = await createWishlist(formData);

if (submit.status === 'success') {
if (submit.data) {
onWishlistCreated(submit.data);
setAccountState({
status: submit.status,
message: t('messages.created', { name: submit.data.name }),
});
}
}

if (submit.status === 'error') {
setAccountState({ status: submit.status, message: submit.message });
}
};

return (
<Form action={onSubmit} className="w-full" onSubmit={(e) => e.stopPropagation()}>
<Field className="relative space-y-2 pb-7" name="name">
<FieldLabel>{t('inputLabel')}</FieldLabel>
<FieldControl asChild>
<Input
id="wishlist"
onChange={handleInputValidation}
onInvalid={handleInputValidation}
required
type="text"
variant={!isInputValid ? 'error' : undefined}
/>
</FieldControl>
<FieldMessage
className="absolute inset-x-0 bottom-0 inline-flex w-full text-xs font-normal text-error"
match="valueMissing"
>
{t('emptyName')}
</FieldMessage>
</Field>
<div className="mt-3 flex">
<SubmitButton />
<DialogCancel asChild>
<Button className="ms-2 w-full lg:w-fit" variant="subtle">
{t('cancel')}
</Button>
</DialogCancel>
</div>
</Form>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { getLocale, getTranslations } from 'next-intl/server';

import { Pagination } from '../../../../(faceted)/_components/pagination';
import { getWishlistQuery } from '../../page-data';
import { TabHeading } from '../tab-heading';

import { WishlistBook } from './wishlist-book';

type WishlistsDetails = NonNullable<Awaited<ReturnType<typeof getWishlistQuery>>>;
export type Wishlists = WishlistsDetails['wishlists'];

interface Props {
wishlists: Wishlists;
pageInfo: WishlistsDetails['pageInfo'];
}

export interface FormStatus {
status: 'success' | 'error';
message: string;
}

export const WISHLISTS_PER_PAGE = 4;

export const WishlistContent = async ({ pageInfo, wishlists }: Props) => {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Pagination' });

const { hasNextPage, hasPreviousPage, startCursor, endCursor } = pageInfo;

return (
<>
<TabHeading heading="wishlists" />
<WishlistBook hasPreviousPage={hasPreviousPage} key={endCursor} wishlists={wishlists} />
<Pagination
endCursor={endCursor}
hasNextPage={hasNextPage}
hasPreviousPage={hasPreviousPage}
nextLabel={t('next')}
prevLabel={t('prev')}
startCursor={startCursor}
/>
</>
);
};
Loading

0 comments on commit b7c28f0

Please sign in to comment.