✨(app-desk) add interaction to sort button
In the team panel, we have the possibility to sort the teams. This commit adds the interaction to the button.
This commit is contained in:
@@ -4,3 +4,22 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #d6dee1;
|
||||
border-radius: 20px;
|
||||
border: 6px solid transparent;
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #a8bbbf;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import { Button, Field, Input } from '@openfun/cunningham-react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Box } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Panel } from '@/features';
|
||||
import { Panel, useCreateTeam } from '@/features';
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
width: fit-content;
|
||||
@@ -14,6 +15,8 @@ const StyledButton = styled(Button)`
|
||||
|
||||
export default function Home() {
|
||||
const { t } = useTranslation();
|
||||
const { mutate: createTeam } = useCreateTeam();
|
||||
const [teamName, setTeamName] = useState('');
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
@@ -24,8 +27,23 @@ export default function Home() {
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$width="100%"
|
||||
$gap="5rem"
|
||||
>
|
||||
<StyledButton>{t('Create a new group')}</StyledButton>
|
||||
<StyledButton>{t('Create a new team')}</StyledButton>
|
||||
<Field>
|
||||
<Input
|
||||
type="text"
|
||||
label={t('Team name')}
|
||||
onChange={(e) => setTeamName(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
fullWidth
|
||||
onClick={() => createTeam(teamName)}
|
||||
className="mt-s"
|
||||
>
|
||||
{t('Create a team')}
|
||||
</Button>
|
||||
</Field>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
1
src/frontend/apps/desk/src/features/teams/api/index.ts
Normal file
1
src/frontend/apps/desk/src/features/teams/api/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './useCreateTeam';
|
||||
@@ -34,7 +34,6 @@ export function useCreateTeam() {
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [KEY_LIST_TEAM],
|
||||
exact: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -20,13 +20,24 @@ interface TeamResponse {
|
||||
accesses: Access[];
|
||||
}
|
||||
|
||||
export enum TeamsOrdering {
|
||||
BY_CREATED_ON = 'created_at',
|
||||
BY_CREATED_ON_DESC = '-created_at',
|
||||
}
|
||||
|
||||
export type TeamsParams = {
|
||||
ordering?: TeamsOrdering;
|
||||
};
|
||||
|
||||
type TeamsResponse = APIList<TeamResponse>;
|
||||
export interface TeamsResponseError {
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export const getTeams = async () => {
|
||||
const response = await fetchAPI(`teams/`);
|
||||
export const getTeams = async (props?: TeamsParams) => {
|
||||
const response = await fetchAPI(
|
||||
`teams/${props?.ordering ? `?ordering=${props.ordering}` : ''}`,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Couldn't fetch teams: ${response.statusText}`);
|
||||
@@ -37,6 +48,7 @@ export const getTeams = async () => {
|
||||
export const KEY_LIST_TEAM = 'teams';
|
||||
|
||||
export function useTeams(
|
||||
param?: TeamsParams,
|
||||
queryConfig?: UseQueryOptions<
|
||||
TeamsResponse,
|
||||
TeamsResponseError,
|
||||
@@ -44,8 +56,8 @@ export function useTeams(
|
||||
>,
|
||||
) {
|
||||
return useQuery<TeamsResponse, TeamsResponseError, TeamsResponse>({
|
||||
queryKey: [KEY_LIST_TEAM],
|
||||
queryFn: getTeams,
|
||||
queryKey: [KEY_LIST_TEAM, param],
|
||||
queryFn: () => getTeams(param),
|
||||
...queryConfig,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import { Box } from '@/components';
|
||||
|
||||
import { default as IconAdd } from '../assets/icon-add.svg?url';
|
||||
import { default as IconSort } from '../assets/icon-sort.svg?url';
|
||||
import { useTeamStore } from '../store/useTeamsStore';
|
||||
|
||||
export const PanelActions = () => {
|
||||
const { t } = useTranslation();
|
||||
const changeOrdering = useTeamStore((state) => state.changeOrdering);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -26,6 +28,7 @@ export const PanelActions = () => {
|
||||
icon={<Image priority src={IconSort} alt={t('Sort teams icon')} />}
|
||||
color="tertiary"
|
||||
className="c__button-no-bg p-0 m-0"
|
||||
onClick={changeOrdering}
|
||||
/>
|
||||
<Button
|
||||
aria-label={t('Add a team')}
|
||||
|
||||
@@ -8,9 +8,13 @@ import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { useTeams } from '../api/useTeams';
|
||||
import IconNone from '../assets/icon-none.svg';
|
||||
import { useTeamStore } from '../store/useTeamsStore';
|
||||
|
||||
export const PanelTeams = () => {
|
||||
const { data, isPending, isError } = useTeams();
|
||||
const ordering = useTeamStore((state) => state.ordering);
|
||||
const { data, isPending, isError } = useTeams({
|
||||
ordering,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
@@ -48,7 +52,7 @@ export const PanelTeams = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Box as="ul" $gap="1rem" className="p-s mt-t">
|
||||
<Box as="ul" $gap="1rem" className="p-s mt-t" $css="overflow:auto;">
|
||||
{data?.results.map((team) => (
|
||||
<Box
|
||||
as="li"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './components/Panel';
|
||||
export * from './components';
|
||||
export * from './api';
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { TeamsOrdering } from '../api/useTeams';
|
||||
|
||||
interface TeamsStore {
|
||||
ordering: TeamsOrdering;
|
||||
changeOrdering: () => void;
|
||||
}
|
||||
|
||||
export const useTeamStore = create<TeamsStore>((set) => ({
|
||||
ordering: TeamsOrdering.BY_CREATED_ON_DESC,
|
||||
changeOrdering: () =>
|
||||
set(({ ordering }) => ({
|
||||
ordering:
|
||||
ordering === TeamsOrdering.BY_CREATED_ON
|
||||
? TeamsOrdering.BY_CREATED_ON_DESC
|
||||
: TeamsOrdering.BY_CREATED_ON,
|
||||
})),
|
||||
}));
|
||||
@@ -1,27 +1,27 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { keyCloakSignIn } from "./common";
|
||||
import { keyCloakSignIn } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page);
|
||||
});
|
||||
|
||||
test.describe("Teams", () => {
|
||||
test("checks all the elements are visible", async ({ page }) => {
|
||||
const panel = page.getByLabel("Teams panel").first();
|
||||
test.describe('Teams', () => {
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
const panel = page.getByLabel('Teams panel').first();
|
||||
|
||||
await expect(panel.getByText("Recents")).toBeVisible();
|
||||
await expect(panel.getByText('Recents')).toBeVisible();
|
||||
|
||||
await expect(
|
||||
panel.getByRole("button", {
|
||||
name: "Sort the teams",
|
||||
panel.getByRole('button', {
|
||||
name: 'Sort the teams',
|
||||
}),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
panel.getByRole("button", {
|
||||
name: "Add a team",
|
||||
panel.getByRole('button', {
|
||||
name: 'Add a team',
|
||||
}),
|
||||
).toBeVisible();
|
||||
|
||||
@@ -31,4 +31,31 @@ test.describe("Teams", () => {
|
||||
),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('check sort button', async ({ page }) => {
|
||||
const panel = page.getByLabel('Teams panel').first();
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await page.getByText('Team name').fill(`team-sort${i}`);
|
||||
await page.getByRole('button', { name: 'Create a team' }).click();
|
||||
await expect(
|
||||
panel.locator('li').getByText(`team-sort${i}`),
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
await panel
|
||||
.getByRole('button', {
|
||||
name: 'Sort the teams',
|
||||
})
|
||||
.click();
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await expect(
|
||||
panel
|
||||
.locator('li')
|
||||
.nth(i)
|
||||
.getByText(`team-sort${i + 1}`),
|
||||
).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user