From 1cb138ecb30c0ba21f811e0a865e7fcd54ae834e Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 3 Apr 2024 11:27:14 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(app-impress)=20create=20feature=20pad?= =?UTF-8?q?s-create?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new feature pads-create for the app impress. It will be used to create a pad in the app. --- .../pads/pads-create/api/useCreatePad.tsx | 41 ++++++++++++ .../pads-create/components/CardCreatePad.tsx | 66 +++++++++++++++++++ .../pads-create/components/InputPadName.tsx | 54 +++++++++++++++ .../pads/pads-create/components/index.ts | 1 + .../src/features/pads/pads-create/index.ts | 1 + .../apps/impress/src/pages/pads/create.tsx | 20 ++++++ .../apps/impress/src/pages/pads/index.tsx | 30 +++++++++ 7 files changed, 213 insertions(+) create mode 100644 src/frontend/apps/impress/src/features/pads/pads-create/api/useCreatePad.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pads-create/components/CardCreatePad.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pads-create/components/InputPadName.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pads-create/components/index.ts create mode 100644 src/frontend/apps/impress/src/features/pads/pads-create/index.ts create mode 100644 src/frontend/apps/impress/src/pages/pads/create.tsx create mode 100644 src/frontend/apps/impress/src/pages/pads/index.tsx diff --git a/src/frontend/apps/impress/src/features/pads/pads-create/api/useCreatePad.tsx b/src/frontend/apps/impress/src/features/pads/pads-create/api/useCreatePad.tsx new file mode 100644 index 00000000..067dfeb9 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pads-create/api/useCreatePad.tsx @@ -0,0 +1,41 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; +import { KEY_LIST_PAD } from '@/features/pads'; + +type CreatePadResponse = { + id: string; + name: string; +}; + +export const createPad = async (name: string): Promise => { + const response = await fetchAPI(`pads/`, { + method: 'POST', + body: JSON.stringify({ + name, + }), + }); + + if (!response.ok) { + throw new APIError('Failed to create the pad', await errorCauses(response)); + } + + return response.json() as Promise; +}; + +interface CreatePadProps { + onSuccess: (data: CreatePadResponse) => void; +} + +export function useCreatePad({ onSuccess }: CreatePadProps) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: createPad, + onSuccess: (data) => { + void queryClient.invalidateQueries({ + queryKey: [KEY_LIST_PAD], + }); + onSuccess(data); + }, + }); +} diff --git a/src/frontend/apps/impress/src/features/pads/pads-create/components/CardCreatePad.tsx b/src/frontend/apps/impress/src/features/pads/pads-create/components/CardCreatePad.tsx new file mode 100644 index 00000000..6b4f70b7 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pads-create/components/CardCreatePad.tsx @@ -0,0 +1,66 @@ +import { Button } from '@openfun/cunningham-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import IconGroup from '@/assets/icons/icon-group2.svg'; +import { Box, Card, StyledLink, Text } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; + +import { useCreatePad } from '../api/useCreatePad'; + +import { InputPadName } from './InputPadName'; + +export const CardCreatePad = () => { + const { t } = useTranslation(); + const router = useRouter(); + const { + mutate: createPad, + isError, + isPending, + error, + } = useCreatePad({ + onSuccess: (pad) => { + router.push(`/pads/${pad.id}`); + }, + }); + const [padName, setPadName] = useState(''); + const { colorsTokens } = useCunninghamTheme(); + + return ( + + + + + + {t('Name the pad')} + + + + + + + + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/pads/pads-create/components/InputPadName.tsx b/src/frontend/apps/impress/src/features/pads/pads-create/components/InputPadName.tsx new file mode 100644 index 00000000..d3d78704 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pads-create/components/InputPadName.tsx @@ -0,0 +1,54 @@ +import { Input, Loader } from '@openfun/cunningham-react'; +import { useEffect, useState } from 'react'; + +import { APIError } from '@/api'; +import { Box, TextErrors } from '@/components'; + +interface InputPadNameProps { + error: APIError | null; + isError: boolean; + isPending: boolean; + label: string; + setPadName: (newPadName: string) => void; + defaultValue?: string; +} + +export const InputPadName = ({ + defaultValue, + error, + isError, + isPending, + label, + setPadName, +}: InputPadNameProps) => { + const [isInputError, setIsInputError] = useState(isError); + + useEffect(() => { + if (isError) { + setIsInputError(true); + } + }, [isError]); + + return ( + <> + { + setPadName(e.target.value); + setIsInputError(false); + }} + rightIcon={edit} + state={isInputError ? 'error' : 'default'} + /> + {isError && error && } + {isPending && ( + + + + )} + + ); +}; diff --git a/src/frontend/apps/impress/src/features/pads/pads-create/components/index.ts b/src/frontend/apps/impress/src/features/pads/pads-create/components/index.ts new file mode 100644 index 00000000..0fd79adc --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pads-create/components/index.ts @@ -0,0 +1 @@ +export * from './CardCreatePad'; diff --git a/src/frontend/apps/impress/src/features/pads/pads-create/index.ts b/src/frontend/apps/impress/src/features/pads/pads-create/index.ts new file mode 100644 index 00000000..07635cbb --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pads-create/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/src/frontend/apps/impress/src/pages/pads/create.tsx b/src/frontend/apps/impress/src/pages/pads/create.tsx new file mode 100644 index 00000000..85f06d4d --- /dev/null +++ b/src/frontend/apps/impress/src/pages/pads/create.tsx @@ -0,0 +1,20 @@ +import { ReactElement } from 'react'; + +import { Box } from '@/components'; +import { CardCreatePad } from '@/features/pads/'; +import { PadLayout } from '@/layouts'; +import { NextPageWithLayout } from '@/types/next'; + +const Page: NextPageWithLayout = () => { + return ( + + + + ); +}; + +Page.getLayout = function getLayout(page: ReactElement) { + return {page}; +}; + +export default Page; diff --git a/src/frontend/apps/impress/src/pages/pads/index.tsx b/src/frontend/apps/impress/src/pages/pads/index.tsx new file mode 100644 index 00000000..684651a4 --- /dev/null +++ b/src/frontend/apps/impress/src/pages/pads/index.tsx @@ -0,0 +1,30 @@ +import { Button } from '@openfun/cunningham-react'; +import type { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +import { Box, StyledLink } from '@/components'; +import { PadLayout } from '@/layouts'; +import { NextPageWithLayout } from '@/types/next'; + +const StyledButton = styled(Button)` + width: fit-content; +`; + +const Page: NextPageWithLayout = () => { + const { t } = useTranslation(); + + return ( + + + {t('Create a new pad')} + + + ); +}; + +Page.getLayout = function getLayout(page: ReactElement) { + return {page}; +}; + +export default Page;