diff --git a/src/frontend/apps/desk/cunningham.ts b/src/frontend/apps/desk/cunningham.ts index 7aed77a..aab556c 100644 --- a/src/frontend/apps/desk/cunningham.ts +++ b/src/frontend/apps/desk/cunningham.ts @@ -259,7 +259,7 @@ const config = { 'border-radius': '0', }, button: { - 'border-radius': '2px', + 'border-radius': '4px', primary: { background: { color: 'var(--c--theme--colors--primary-text)', @@ -270,29 +270,47 @@ const config = { 'color-hover': '#ffffff', 'color-active': '#ffffff', }, + secondary: { + background: { + 'color-hover': 'var(--c--theme--colors--primary-100)', + 'color-active': 'var(--c--theme--colors--primary-200)', + }, + border: { + 'color-hover': 'var(--c--theme--colors--primary-300)', + }, + color: 'var(--c--theme--colors--primary-text)', + }, }, 'forms-checkbox': { 'border-radius': '0', }, + 'forms-datepicker': { + 'border-radius': '0', + }, + 'forms-fileuploader': { + 'border-radius': '0', + }, + 'forms-input': { + 'border-radius': '4px', + 'background-color': '#ffffff', + 'border-color': 'var(--c--theme--colors--primary-text)', + 'box-shadow-color': 'var(--c--theme--colors--primary-text)', + }, + 'forms-labelledbox': { + 'label-color': { + big: 'var(--c--theme--colors--primary-text)', + }, + }, + 'forms-select': { + 'border-radius': '0', + }, 'forms-switch': { 'handle-border-radius': '2px', 'rail-border-radius': '4px', }, - 'forms-input': { - 'border-radius': '0', - }, - 'forms-select': { - 'border-radius': '0', - }, - 'forms-datepicker': { - 'border-radius': '0', - }, 'forms-textarea': { 'border-radius': '0', }, - 'forms-fileuploader': { - 'border-radius': '0', - }, }, }, }, diff --git a/src/frontend/apps/desk/src/__tests__/pages.test.tsx b/src/frontend/apps/desk/src/__tests__/pages.test.tsx index 1daa77a..ce4573e 100644 --- a/src/frontend/apps/desk/src/__tests__/pages.test.tsx +++ b/src/frontend/apps/desk/src/__tests__/pages.test.tsx @@ -9,8 +9,6 @@ describe('Page', () => { it('checks Page rendering', () => { render(, { wrapper: AppWrapper }); - expect(screen.getByRole('status')).toBeInTheDocument(); - expect( screen.getByRole('button', { name: /Create a new team/i, diff --git a/src/frontend/apps/desk/src/assets/icons/icon-group2.svg b/src/frontend/apps/desk/src/assets/icons/icon-group2.svg new file mode 100644 index 0000000..845da48 --- /dev/null +++ b/src/frontend/apps/desk/src/assets/icons/icon-group2.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/src/frontend/apps/desk/src/components/Box.tsx b/src/frontend/apps/desk/src/components/Box.tsx index f51ca6f..2f2cd0e 100644 --- a/src/frontend/apps/desk/src/components/Box.tsx +++ b/src/frontend/apps/desk/src/components/Box.tsx @@ -17,6 +17,8 @@ export interface BoxProps { $position?: CSSProperties['position']; $radius?: CSSProperties['borderRadius']; $width?: CSSProperties['width']; + $maxWidth?: CSSProperties['maxWidth']; + $minWidth?: CSSProperties['minWidth']; } export type BoxType = ComponentPropsWithRef; @@ -36,5 +38,7 @@ export const Box = styled('div')` ${({ $position }) => $position && `position: ${$position};`} ${({ $radius }) => $radius && `border-radius: ${$radius};`} ${({ $width }) => $width && `width: ${$width};`} + ${({ $maxWidth }) => $maxWidth && `max-width: ${$maxWidth};`} + ${({ $minWidth }) => $minWidth && `min-width: ${$minWidth};`} ${({ $css }) => $css && `${$css};`} `; diff --git a/src/frontend/apps/desk/src/components/Card.tsx b/src/frontend/apps/desk/src/components/Card.tsx new file mode 100644 index 0000000..6450603 --- /dev/null +++ b/src/frontend/apps/desk/src/components/Card.tsx @@ -0,0 +1,28 @@ +import { PropsWithChildren } from 'react'; + +import { useCunninghamTheme } from '@/cunningham'; + +import { Box, BoxType } from '.'; + +export const Card = ({ + children, + $css, + ...props +}: PropsWithChildren) => { + const { colorsTokens } = useCunninghamTheme(); + + return ( + + {children} + + ); +}; diff --git a/src/frontend/apps/desk/src/components/index.ts b/src/frontend/apps/desk/src/components/index.ts index c0ed256..ee27428 100644 --- a/src/frontend/apps/desk/src/components/index.ts +++ b/src/frontend/apps/desk/src/components/index.ts @@ -1,3 +1,4 @@ export * from './Box'; export * from './Text'; export * from './Link'; +export * from './Card'; diff --git a/src/frontend/apps/desk/src/cunningham/cunningham-custom-tokens.css b/src/frontend/apps/desk/src/cunningham/cunningham-custom-tokens.css index 9baa12b..885bd8a 100644 --- a/src/frontend/apps/desk/src/cunningham/cunningham-custom-tokens.css +++ b/src/frontend/apps/desk/src/cunningham/cunningham-custom-tokens.css @@ -25,7 +25,4 @@ --c--components--forms-select--value-color--disabled: var( --c--theme--colors--greyscale-400 ); - --c--components--forms-labelledbox--label-color--big: var( - --c--theme--colors--primary-500 - ); } diff --git a/src/frontend/apps/desk/src/cunningham/cunningham-style.css b/src/frontend/apps/desk/src/cunningham/cunningham-style.css index e99b5cb..b4f8b01 100644 --- a/src/frontend/apps/desk/src/cunningham/cunningham-style.css +++ b/src/frontend/apps/desk/src/cunningham/cunningham-style.css @@ -17,7 +17,7 @@ } .labelled-box label { - color: var(--c--theme--colors--primary-500); + color: var(--c--theme--colors--primary-text); } .labelled-box--disabled label { @@ -53,7 +53,7 @@ .c__input__wrapper:hover, .c__textarea__wrapper:hover { - box-shadow: var(--c--theme--colors--primary-500) 0 0 0 2px; + box-shadow: var(--c--components--forms-input--box-shadow-color) 0 0 0 2px; } .c__textarea__wrapper--disabled:hover, @@ -325,6 +325,7 @@ input:-webkit-autofill:focus { --c--components--button--secondary--background--color-hover ); color: var(--c--components--button--secondary--color-hover); + border: 1px solid var(--c--components--button--secondary--border--color-hover); } .c__button--tertiary { diff --git a/src/frontend/apps/desk/src/cunningham/cunningham-tokens.css b/src/frontend/apps/desk/src/cunningham/cunningham-tokens.css index 5c605dd..2377c78 100644 --- a/src/frontend/apps/desk/src/cunningham/cunningham-tokens.css +++ b/src/frontend/apps/desk/src/cunningham/cunningham-tokens.css @@ -387,7 +387,7 @@ --c--theme--font--families--accent: marianne; --c--theme--font--families--base: marianne; --c--components--alert--border-radius: 0; - --c--components--button--border-radius: 2px; + --c--components--button--border-radius: 4px; --c--components--button--primary--background--color: var( --c--theme--colors--primary-text ); @@ -400,14 +400,36 @@ --c--components--button--primary--color: #fff; --c--components--button--primary--color-hover: #fff; --c--components--button--primary--color-active: #fff; + --c--components--button--secondary--background--color-hover: var( + --c--theme--colors--primary-100 + ); + --c--components--button--secondary--background--color-active: var( + --c--theme--colors--primary-200 + ); + --c--components--button--secondary--border--color-hover: var( + --c--theme--colors--primary-300 + ); + --c--components--button--secondary--color: var( + --c--theme--colors--primary-text + ); --c--components--forms-checkbox--border-radius: 0; + --c--components--forms-datepicker--border-radius: 0; + --c--components--forms-fileuploader--border-radius: 0; + --c--components--forms-input--border-radius: 4px; + --c--components--forms-input--background-color: #fff; + --c--components--forms-input--border-color: var( + --c--theme--colors--primary-text + ); + --c--components--forms-input--box-shadow-color: var( + --c--theme--colors--primary-text + ); + --c--components--forms-labelledbox--label-color--big: var( + --c--theme--colors--primary-text + ); + --c--components--forms-select--border-radius: 0; --c--components--forms-switch--handle-border-radius: 2px; --c--components--forms-switch--rail-border-radius: 4px; - --c--components--forms-input--border-radius: 0; - --c--components--forms-select--border-radius: 0; - --c--components--forms-datepicker--border-radius: 0; --c--components--forms-textarea--border-radius: 0; - --c--components--forms-fileuploader--border-radius: 0; } .clr-secondary-text { diff --git a/src/frontend/apps/desk/src/cunningham/cunningham-tokens.ts b/src/frontend/apps/desk/src/cunningham/cunningham-tokens.ts index d860bd2..3e9ee6d 100644 --- a/src/frontend/apps/desk/src/cunningham/cunningham-tokens.ts +++ b/src/frontend/apps/desk/src/cunningham/cunningham-tokens.ts @@ -398,7 +398,7 @@ export const tokens = { components: { alert: { 'border-radius': '0' }, button: { - 'border-radius': '2px', + 'border-radius': '4px', primary: { background: { color: 'var(--c--theme--colors--primary-text)', @@ -409,17 +409,33 @@ export const tokens = { 'color-hover': '#ffffff', 'color-active': '#ffffff', }, + secondary: { + background: { + 'color-hover': 'var(--c--theme--colors--primary-100)', + 'color-active': 'var(--c--theme--colors--primary-200)', + }, + border: { 'color-hover': 'var(--c--theme--colors--primary-300)' }, + color: 'var(--c--theme--colors--primary-text)', + }, }, 'forms-checkbox': { 'border-radius': '0' }, + 'forms-datepicker': { 'border-radius': '0' }, + 'forms-fileuploader': { 'border-radius': '0' }, + 'forms-input': { + 'border-radius': '4px', + 'background-color': '#ffffff', + 'border-color': 'var(--c--theme--colors--primary-text)', + 'box-shadow-color': 'var(--c--theme--colors--primary-text)', + }, + 'forms-labelledbox': { + 'label-color': { big: 'var(--c--theme--colors--primary-text)' }, + }, + 'forms-select': { 'border-radius': '0' }, 'forms-switch': { 'handle-border-radius': '2px', 'rail-border-radius': '4px', }, - 'forms-input': { 'border-radius': '0' }, - 'forms-select': { 'border-radius': '0' }, - 'forms-datepicker': { 'border-radius': '0' }, 'forms-textarea': { 'border-radius': '0' }, - 'forms-fileuploader': { 'border-radius': '0' }, }, }, }, diff --git a/src/frontend/apps/desk/src/features/teams/components/Panel.tsx b/src/frontend/apps/desk/src/features/teams/components/Panel.tsx index a757701..9066c84 100644 --- a/src/frontend/apps/desk/src/features/teams/components/Panel.tsx +++ b/src/frontend/apps/desk/src/features/teams/components/Panel.tsx @@ -13,7 +13,9 @@ export const Panel = () => { return ( { const commonProps = { className: 'p-t', - width: 36, + width: 52, style: { borderRadius: '10px', + flexShrink: 0, }, }; diff --git a/src/frontend/apps/desk/src/i18n/translations.json b/src/frontend/apps/desk/src/i18n/translations.json index 0b3a097..a719ecd 100644 --- a/src/frontend/apps/desk/src/i18n/translations.json +++ b/src/frontend/apps/desk/src/i18n/translations.json @@ -1,8 +1,6 @@ { "fr": { "translation": { - "Create a new team": "Créer un nouveau groupe", - "Team name": "Nom du groupe", "Create a team": "Créer un groupe", "Marianne Logo": "Logo Marianne", "Freedom Equality Fraternity Logo": "Logo Liberté Égalité Fraternité", @@ -33,27 +31,21 @@ "Something bad happens, please refresh the page": "Une erreur inattendue s'est produite, rechargez la page.", "0 group to display": "0 groupe à afficher.", "Create your first team by clicking on the \"Create a new team\" button": "Créez votre premier groupe en cliquant sur le bouton \"Créer un nouveau groupe\".", + "Create new team card": "Carte créer une nouvelle équipe", "Something bad happens, please retry.": "Une erreur inattendue s'est produite, rechargez la page.", "0 group to display.": "0 groupe à afficher.", "Create your first team by clicking on the \"Create a new team\" button.": "Créez votre premier groupe en cliquant sur le bouton \"Créer un nouveau groupe\".", "Something bad happens, please refresh the page.": "Une erreur inattendue s'est produite, rechargez la page.", - "icon group": "icône groupe", - "Members of “{{teamName}}“": "Membres de “{{teamName}}“", - "Add people to the “{{teamName}}“ group.": "Ajouter des personnes au groupe “{{teamName}}“.", - "{{count}} member_one": "{{count}} membre", - "{{count}} member_many": "{{count}} membres", - "{{count}} member_other": "{{count}} membres", - "Created at {{created_at}}": "Créé le {{created_at}}", - "Last update at {{updated_at}}": "Dernière modification le {{updated_at}}", "People": "People", "People Description": "Description de People", - "404 - Page not found": "404 - Page introuvable", + "Something bad happens, please retry": "Une erreur inattendue s'est produite, rechargez la page.", "Panel create new team": "Panneau de création d'un nouveau groupe", + "icon group": "icône groupe", "Name the team": "Nommer le groupe", + "Team name": "Nom du groupe", "Cancel": "Annuler", "Create the team": "Créer le groupe", - "Something bad happens, please retry": "Une erreur inattendue s'est produite, rechargez la page.", - "Add people to the “{{teamName}}“ group": "Ajouter des personnes au groupe «{{teamName}}»." + "Create a new team": "Créer un nouveau groupe" } } } diff --git a/src/frontend/apps/desk/src/pages/globals.css b/src/frontend/apps/desk/src/pages/globals.css index 174c2f9..7d81925 100644 --- a/src/frontend/apps/desk/src/pages/globals.css +++ b/src/frontend/apps/desk/src/pages/globals.css @@ -5,6 +5,10 @@ body { padding: 0; } +* { + box-sizing: border-box; +} + ::-webkit-scrollbar { width: 20px; } diff --git a/src/frontend/apps/desk/src/pages/index.tsx b/src/frontend/apps/desk/src/pages/index.tsx index 1ba7992..f38fbc4 100644 --- a/src/frontend/apps/desk/src/pages/index.tsx +++ b/src/frontend/apps/desk/src/pages/index.tsx @@ -3,7 +3,7 @@ import type { ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import { StyledLink } from '@/components'; +import { Box, StyledLink } from '@/components'; import { NextPageWithLayout } from '@/types/next'; import TeamLayout from './teams/TeamLayout'; @@ -16,9 +16,11 @@ const Page: NextPageWithLayout = () => { const { t } = useTranslation(); return ( - - {t('Create a new team')} - + + + {t('Create a new team')} + + ); }; diff --git a/src/frontend/apps/desk/src/pages/teams/TeamLayout.tsx b/src/frontend/apps/desk/src/pages/teams/TeamLayout.tsx index 389854c..1241110 100644 --- a/src/frontend/apps/desk/src/pages/teams/TeamLayout.tsx +++ b/src/frontend/apps/desk/src/pages/teams/TeamLayout.tsx @@ -15,11 +15,8 @@ export default function TeamLayout({ children }: PropsWithChildren) { {children} diff --git a/src/frontend/apps/desk/src/pages/teams/create.tsx b/src/frontend/apps/desk/src/pages/teams/create.tsx index 0878340..4ed3312 100644 --- a/src/frontend/apps/desk/src/pages/teams/create.tsx +++ b/src/frontend/apps/desk/src/pages/teams/create.tsx @@ -1,7 +1,10 @@ -import { Button, Field, Input } from '@openfun/cunningham-react'; +import { Button, Input, Loader } from '@openfun/cunningham-react'; import { ReactElement, 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 { useCreateTeam } from '@/features/teams'; import { NextPageWithLayout } from '@/types/next'; @@ -9,20 +12,60 @@ import TeamLayout from './TeamLayout'; const Page: NextPageWithLayout = () => { const { t } = useTranslation(); - const { mutate: createTeam } = useCreateTeam(); + const { mutate: createTeam, isError, isPending } = useCreateTeam(); const [teamName, setTeamName] = useState(''); + const { colorsTokens } = useCunninghamTheme(); return ( - - setTeamName(e.target.value)} - /> - - + + + + + + + {t('Name the team')} + + + setTeamName(e.target.value)} + rightIcon={edit} + /> + {isError && ( + + {t('Something bad happens, please retry.')} + + )} + {isPending && ( + + + + )} + + + + + + + + + ); }; diff --git a/src/frontend/apps/e2e/__tests__/app-desk/teams-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/teams-create.spec.ts new file mode 100644 index 0000000..48a469a --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-desk/teams-create.spec.ts @@ -0,0 +1,61 @@ +import { expect, test } from '@playwright/test'; + +import { keyCloakSignIn } from './common'; + +test.beforeEach(async ({ page, browserName }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName); +}); + +test.describe('Teams', () => { + test('checks all the create team elements are visible', async ({ page }) => { + const buttonCreateHomepage = page.getByRole('button', { + name: 'Create a new team', + }); + await buttonCreateHomepage.click(); + await expect(buttonCreateHomepage).toBeHidden(); + + const card = page.getByLabel('Create new team card').first(); + + await expect(card.getByLabel('Team name')).toBeVisible(); + + await expect(card.getByLabel('icon group')).toBeVisible(); + + await expect( + card.getByRole('heading', { + name: 'Name the team', + level: 3, + }), + ).toBeVisible(); + + await expect( + card.getByRole('button', { + name: 'Create the team', + }), + ).toBeVisible(); + + await expect( + card.getByRole('button', { + name: 'Cancel', + }), + ).toBeVisible(); + }); + + test('checks the cancel button interaction', async ({ page }) => { + const buttonCreateHomepage = page.getByRole('button', { + name: 'Create a new team', + }); + await buttonCreateHomepage.click(); + await expect(buttonCreateHomepage).toBeHidden(); + + const card = page.getByLabel('Create new team card').first(); + + await card + .getByRole('button', { + name: 'Cancel', + }) + .click(); + + await expect(buttonCreateHomepage).toBeVisible(); + }); +}); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/teams.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts similarity index 82% rename from src/frontend/apps/e2e/__tests__/app-desk/teams.spec.ts rename to src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts index e9fa125..e952c0d 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/teams.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts @@ -10,7 +10,7 @@ test.beforeEach(async ({ page, browserName }) => { }); test.describe.configure({ mode: 'serial' }); -test.describe('Teams', () => { +test.describe('Teams Panel', () => { test('001 - checks all the elements are visible', async ({ page }) => { const panel = page.getByLabel('Teams panel').first(); @@ -35,10 +35,10 @@ test.describe('Teams', () => { ).toBeVisible(); }); - test('002 - check sort button', async ({ page, browserName }) => { + test('002 - checks the sort button', async ({ page, browserName }) => { const panel = page.getByLabel('Teams panel').first(); - await page.getByRole('button', { name: 'Add a team' }).click(); + await panel.getByRole('button', { name: 'Add a team' }).click(); const randomTeams = Array.from({ length: 3 }, () => { return `team-sort-${browserName}-${Math.floor(Math.random() * 1000)}`; @@ -46,7 +46,7 @@ test.describe('Teams', () => { for (let i = 0; i < 3; i++) { await page.getByText('Team name').fill(`${randomTeams[i]}-${i}`); - await page.getByRole('button', { name: 'Create a team' }).click(); + await page.getByRole('button', { name: 'Create the team' }).click(); await expect( panel.locator('li').nth(0).getByText(`${randomTeams[i]}-${i}`), ).toBeVisible(); @@ -65,18 +65,18 @@ test.describe('Teams', () => { } }); - test('003 - check the infinite scrool', async ({ page, browserName }) => { + test('003 - checks the infinite scrool', async ({ page, browserName }) => { test.setTimeout(90000); const panel = page.getByLabel('Teams panel').first(); - await page.getByRole('button', { name: 'Add a team' }).click(); + await panel.getByRole('button', { name: 'Add a team' }).click(); const randomTeams = Array.from({ length: 40 }, () => { return `team-infinite-${browserName}-${Math.floor(Math.random() * 10000)}`; }); for (let i = 0; i < 40; i++) { await page.getByText('Team name').fill(`${randomTeams[i]}-${i}`); - await page.getByRole('button', { name: 'Create Team' }).click(); + await page.getByRole('button', { name: 'Create the team' }).click(); await expect( panel.locator('li').getByText(`${randomTeams[i]}-${i}`), ).toBeVisible();