From b517b0bc395420ab883fae82bfbd4b78e7e4a40a Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 3 Apr 2024 11:27:54 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(app-impress)=20create=20feature=20pad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new feature pad for the app impress. It will be used to display a pad in the app. --- .../src/features/pads/pad/api/index.ts | 1 + .../src/features/pads/pad/api/usePad.tsx | 32 +++++++ .../features/pads/pad/components/PadInfo.tsx | 90 +++++++++++++++++++ .../src/features/pads/pad/components/index.ts | 1 + .../impress/src/features/pads/pad/index.tsx | 3 + .../impress/src/features/pads/pad/types.tsx | 22 +++++ .../apps/impress/src/pages/pads/[id].tsx | 56 ++++++++++++ 7 files changed, 205 insertions(+) create mode 100644 src/frontend/apps/impress/src/features/pads/pad/api/index.ts create mode 100644 src/frontend/apps/impress/src/features/pads/pad/api/usePad.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pad/components/PadInfo.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pad/components/index.ts create mode 100644 src/frontend/apps/impress/src/features/pads/pad/index.tsx create mode 100644 src/frontend/apps/impress/src/features/pads/pad/types.tsx create mode 100644 src/frontend/apps/impress/src/pages/pads/[id].tsx diff --git a/src/frontend/apps/impress/src/features/pads/pad/api/index.ts b/src/frontend/apps/impress/src/features/pads/pad/api/index.ts new file mode 100644 index 00000000..a995b80b --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/api/index.ts @@ -0,0 +1 @@ +export * from './usePad'; diff --git a/src/frontend/apps/impress/src/features/pads/pad/api/usePad.tsx b/src/frontend/apps/impress/src/features/pads/pad/api/usePad.tsx new file mode 100644 index 00000000..cef5af84 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/api/usePad.tsx @@ -0,0 +1,32 @@ +import { UseQueryOptions, useQuery } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; + +import { Pad } from '../types'; + +export type PadParams = { + id: string; +}; + +export const getPad = async ({ id }: PadParams): Promise => { + const response = await fetchAPI(`pads/${id}`); + + if (!response.ok) { + throw new APIError('Failed to get the pad', await errorCauses(response)); + } + + return response.json() as Promise; +}; + +export const KEY_PAD = 'pad'; + +export function usePad( + param: PadParams, + queryConfig?: UseQueryOptions, +) { + return useQuery({ + queryKey: [KEY_PAD, param], + queryFn: () => getPad(param), + ...queryConfig, + }); +} diff --git a/src/frontend/apps/impress/src/features/pads/pad/components/PadInfo.tsx b/src/frontend/apps/impress/src/features/pads/pad/components/PadInfo.tsx new file mode 100644 index 00000000..8f8fdb7a --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/components/PadInfo.tsx @@ -0,0 +1,90 @@ +import { DateTime, DateTimeFormatOptions } from 'luxon'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import IconGroup from '@/assets/icons/icon-group2.svg'; +import { Box, Card, Text } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; + +import { Pad, Role } from '../types'; + +const format: DateTimeFormatOptions = { + month: '2-digit', + day: '2-digit', + year: 'numeric', +}; + +interface PadInfoProps { + pad: Pad; + currentRole: Role; +} + +export const PadInfo = ({ pad }: PadInfoProps) => { + const { t } = useTranslation(); + const { colorsTokens } = useCunninghamTheme(); + const { i18n } = useTranslation(); + + const created_at = DateTime.fromISO(pad.created_at) + .setLocale(i18n.language) + .toLocaleString(format); + + const updated_at = DateTime.fromISO(pad.updated_at) + .setLocale(i18n.language) + .toLocaleString(format); + + return ( + <> + + + + + + {t('Members of “{{padName}}“', { + padName: pad.name, + })} + + + {t('Add people to the “{{padName}}“ group.', { + padName: pad.name, + })} + + + + + + {t('{{count}} member', { count: pad.accesses.length })} + + + {t('Created at')}  + + {created_at} + + + + {t('Last update at')}  + + {updated_at} + + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/pads/pad/components/index.ts b/src/frontend/apps/impress/src/features/pads/pad/components/index.ts new file mode 100644 index 00000000..dc4c4859 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/components/index.ts @@ -0,0 +1 @@ +export * from './PadInfo'; diff --git a/src/frontend/apps/impress/src/features/pads/pad/index.tsx b/src/frontend/apps/impress/src/features/pads/pad/index.tsx new file mode 100644 index 00000000..314dad0c --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/index.tsx @@ -0,0 +1,3 @@ +export * from './api'; +export * from './components'; +export * from './types'; diff --git a/src/frontend/apps/impress/src/features/pads/pad/types.tsx b/src/frontend/apps/impress/src/features/pads/pad/types.tsx new file mode 100644 index 00000000..31cbc236 --- /dev/null +++ b/src/frontend/apps/impress/src/features/pads/pad/types.tsx @@ -0,0 +1,22 @@ +import { Access } from '@/features/members'; + +export enum Role { + MEMBER = 'member', + ADMIN = 'administrator', + OWNER = 'owner', +} + +export interface Pad { + id: string; + name: string; + accesses: Access[]; + created_at: string; + updated_at: string; + abilities: { + delete: boolean; + get: boolean; + manage_accesses: boolean; + patch: boolean; + put: boolean; + }; +} diff --git a/src/frontend/apps/impress/src/pages/pads/[id].tsx b/src/frontend/apps/impress/src/pages/pads/[id].tsx new file mode 100644 index 00000000..8164afeb --- /dev/null +++ b/src/frontend/apps/impress/src/pages/pads/[id].tsx @@ -0,0 +1,56 @@ +import { Loader } from '@openfun/cunningham-react'; +import { useRouter as useNavigate } from 'next/navigation'; +import { useRouter } from 'next/router'; +import { ReactElement } from 'react'; + +import { Box } from '@/components'; +import { TextErrors } from '@/components/TextErrors'; +import { usePad } from '@/features/pads'; +import { PadLayout } from '@/layouts'; +import { NextPageWithLayout } from '@/types/next'; + +const Page: NextPageWithLayout = () => { + const { + query: { id }, + } = useRouter(); + + if (typeof id !== 'string') { + throw new Error('Invalid pad id'); + } + + return ; +}; + +interface PadProps { + id: string; +} + +const Pad = ({ id }: PadProps) => { + const { data: pad, isLoading, isError, error } = usePad({ id }); + const navigate = useNavigate(); + + if (isError && error) { + if (error.status === 404) { + navigate.replace(`/404`); + return null; + } + + return ; + } + + if (isLoading || !pad) { + return ( + + + + ); + } + + return <>Toto; +}; + +Page.getLayout = function getLayout(page: ReactElement) { + return {page}; +}; + +export default Page;