Skip to content

Commit

Permalink
add pages edit for publish an admin activity
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaume-pages committed Oct 16, 2024
1 parent c353e89 commit 9aeff9c
Show file tree
Hide file tree
Showing 16 changed files with 366 additions and 86 deletions.
13 changes: 13 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"@types/jsonwebtoken": "8.5.8",
"@types/leaflet": "1.7.11",
"@types/leaflet.fullscreen": "1.6.1",
"@types/lodash": "^4",
"@types/md5": "2.3.2",
"@types/mime-types": "2.1.1",
"@types/morgan": "1.9.3",
Expand Down Expand Up @@ -174,6 +175,7 @@
"jszip": "^3.10.1",
"leaflet": "^1.8.0",
"leaflet.fullscreen": "^2.4.0",
"lodash": "^4.17.21",
"maplibre-gl": "2.1.9",
"md5": "^2.3.0",
"mime-types": "^2.1.35",
Expand Down
81 changes: 62 additions & 19 deletions server/controllers/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,27 +536,70 @@ activityController.delete({ path: '/:id', userType: UserType.TEACHER }, async (r
res.status(204).send();
});

activityController.delete({ path: '/admin/:id', userType: UserType.TEACHER }, async (req: Request, res: Response) => {
const id = parseInt(req.params.id, 10) || 0;
const activity = await AppDataSource.getRepository(Activity).findOne({ where: { id } });
if (activity === null || req.user === undefined) {
res.status(204).send();
return;
}
if (activity.userId !== req.user.id && req.user.type > UserType.ADMIN) {
activityController.delete(
{ path: '/admin/:id', userType: UserType.SUPER_ADMIN | UserType.ADMIN | UserType.MEDIATOR },
async (req: Request, res: Response) => {
const id = parseInt(req.params.id, 10) || 0;
const activity = await AppDataSource.getRepository(Activity).findOne({ where: { id } });
if (activity === null || req.user === undefined) {
res.status(204).send();
return;
}
if (activity.userId !== req.user.id && req.user.type > UserType.ADMIN) {
res.status(204).send();
return;
}

if (activity.status === ActivityStatus.DRAFT) {
// No soft delete for drafts.
await AppDataSource.getRepository(Activity).delete({ id });
} else {
await AppDataSource.createQueryBuilder().delete().from(Activity).where('parentActivityId = :id', { id: activity.id }).execute();
await AppDataSource.getRepository(Activity).softDelete({ id });
}
res.status(204).send();
return;
}
},
);

if (activity.status === ActivityStatus.DRAFT) {
// No soft delete for drafts.
await AppDataSource.getRepository(Activity).delete({ id });
} else {
await AppDataSource.createQueryBuilder().delete().from(Activity).where('parentActivityId = :id', { id: activity.id }).execute();
await AppDataSource.getRepository(Activity).softDelete({ id });
}
res.status(204).send();
});
activityController.get(
{ path: '/children', userType: UserType.SUPER_ADMIN | UserType.ADMIN | UserType.MEDIATOR },
async (req: Request, res: Response) => {
const id = req.query.id;
const activities = await AppDataSource.getRepository(Activity)
.createQueryBuilder('Activity')
.where('Activity.parentActivityId = :id', { id })
.getMany();
res.sendJSON(activities);
},
);

activityController.put(
{
path: '/admin/:id',
userType: UserType.SUPER_ADMIN | UserType.ADMIN | UserType.MEDIATOR,
},
async (req: Request, res: Response) => {
const { id } = req.params;
const { phase } = req.body;

try {
const activityRepository = AppDataSource.getRepository(Activity);
const activity = await activityRepository.findOneBy({ id: Number(id) });

if (!activity) {
return res.status(404).sendJSON({ message: 'Activité non existante' });
}

activity.phase = phase;
await activityRepository.save(activity);

return res.sendJSON({ message: 'Phase updated successfully', activity });
} catch (error) {
console.error('Error updating phase:', error);
return res.status(500).sendJSON({ message: 'Internal Server Error' });
}
},
);

// --- Add comment controllers
activityController.router.use(`/:id${commentController.name}`, commentController.router);
Expand Down
2 changes: 1 addition & 1 deletion src/api/activities/activities.admin.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export async function postAdminActivity({ activityParentId, phase, villages }: P
},
});
if (response.error) {
throw new Error('La publication a échoué');
throw new Error('La publication a échouée');
}
return response.data;
}
18 changes: 18 additions & 0 deletions src/api/activities/activities.admin.put.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useMutation } from 'react-query';

import { axiosRequest } from 'src/utils/axiosRequest';

async function updateActivityPhase({ activityId, phase }: { activityId: number; phase: number }) {
return await axiosRequest({
method: 'PUT',
baseURL: '/api',
url: `/activities/admin/${activityId}`,
data: { phase },
});
}

export const useUpdateActivityPhase = () => {
return useMutation(({ activityId, phase }: { activityId: number; phase: number }) => {
return updateActivityPhase({ activityId, phase });
});
};
22 changes: 22 additions & 0 deletions src/api/activities/activities.adminGetChildren.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useQuery } from 'react-query';

import { axiosRequest } from 'src/utils/axiosRequest';

async function getChildrenActivitiesById(params: { id: number }) {
const { id } = params;
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: `/activities/children`,
params: {
id,
},
})
).data;
}

export const useGetChildrenActivitiesById = (args: { id: number }) => {
const { id } = args;
return useQuery(['childrenActivities', id], () => getChildrenActivitiesById({ id }));
};
2 changes: 1 addition & 1 deletion src/api/activities/activities.getOneById.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ async function getOneActivityById(params: { id: number }) {

export const useGetOneActivityById = (args: { id: number }) => {
const { id } = args;
return useQuery(['activities', id], () => getOneActivityById({ id }));
return useQuery(['activityById', id], () => getOneActivityById({ id }));
};
4 changes: 4 additions & 0 deletions src/components/activities/ActivityCard/GameCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ const phrase = {
export const GameCard = ({ activity, isSelf, noButtons, isDraft, showEditButtons, onDelete, gameType }: GameCardProps) => {
const [totalGamesCount, setTotalGamesCount] = useState<number>(0);
const [availableGamesCount, setAvailableGamesCount] = useState<number>(0);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { data: countAbleToPlay } = useCountAbleToPlayStandardGame(gameType, activity.villageId);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { data: countAllStandardGame } = useCountAllStandardGame(gameType, activity.villageId);
const typeOfGame = TYPE_OF_GAME[gameType];
const path = `/creer-un-jeu/${typeOfGame}/displayList`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ import { usePublishActivity } from 'src/api/activities/activities.put';
import PelicoSouriant from 'src/svg/pelico/pelico-souriant.svg';
import { htmlToText } from 'src/utils';

export default function ActivityCard(activity: Pick<Activity, 'images' | 'content' | 'phase' | 'data' | 'id' | 'status'>) {
export default function ActivityCard({
activity,
modifiedDisabled,
}: {
activity: Pick<Activity, 'images' | 'content' | 'phase' | 'data' | 'id' | 'status'>;
modifiedDisabled: boolean;
}) {
const publishActivity = usePublishActivity({ activityId: activity.id });
const queryClient = useQueryClient();
const router = useRouter();
Expand All @@ -39,7 +45,7 @@ export default function ActivityCard(activity: Pick<Activity, 'images' | 'conten
};
const handleModified = () => {
if (activity.status === 0) {
router.push(`/admin/newportal/publier/prepublish/${activity.id}`);
router.push(`/admin/newportal/publier/prepublish/edit/${activity.id}`);
} else {
router.push(`/admin/newportal/contenulibre/edit/1/${activity.id}`);
}
Expand Down Expand Up @@ -91,7 +97,9 @@ export default function ActivityCard(activity: Pick<Activity, 'images' | 'conten
'aria-labelledby': 'basic-button',
}}
>
<MenuItem onClick={handleModified}>Modifier</MenuItem>
<MenuItem onClick={handleModified} disabled={modifiedDisabled}>
Modifier
</MenuItem>
<MenuItem onClick={handleDelete}>Supprimer</MenuItem>
</Menu>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ type Props = {
svgNoData: React.ReactNode;
noDataText: string;
buttonAction: () => void;
modifiedDisabled?: boolean;
};

export default function ActivityCardAdminList({ title, activities, svgNoData, noDataText, buttonAction }: Props) {
export default function ActivityCardAdminList({ title, activities, svgNoData, noDataText, buttonAction, modifiedDisabled }: Props) {
const isMobile = useMediaQuery('(max-width: 768px)');

return (
Expand Down Expand Up @@ -45,7 +46,9 @@ export default function ActivityCardAdminList({ title, activities, svgNoData, no
<div style={{ display: 'flex', flexDirection: isMobile ? 'column' : 'row' }}>
{activities.map((activity) => (
<div key={activity.id} style={{ width: isMobile ? '100%' : '50%' }}>
<ActivityCardAdmin {...activity} />
{/* eslint-disable-next-line */}
{/* @ts-ignore */}
<ActivityCardAdmin activity={activity} modifiedDisabled={modifiedDisabled} />
</div>
))}
</div>
Expand Down
15 changes: 5 additions & 10 deletions src/pages/admin/newportal/contenulibre/edit/2/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Image from 'next/image';
import { useRouter } from 'next/router';
import React from 'react';
import { QueryClient } from 'react-query';

import { TextField, Switch, Button } from '@mui/material';

Expand Down Expand Up @@ -28,33 +29,27 @@ const ContenuLibre = () => {
const [selectedImageUrl, setSelectedImageUrl] = React.useState<string | undefined>(undefined);
const [isAllImagesModalOpen, setIsAllImagesModalOpen] = React.useState(false);
const [isImageModalOpen, setIsImageModalOpen] = React.useState(false);
const queryClient = new QueryClient();

const data = (activity?.data as FreeContentData) || null;

const hasContentImages = React.useMemo(() => activity !== null && activity.content.some((c: { type: string }) => c.type === 'image'), [activity]);
const imageUrl = React.useMemo(() => getImage(activity?.content ?? [], data), [activity, data]);
const [localData, setLocalData] = React.useState<FreeContentData | null>(null);

// Utilise useEffect pour synchroniser l'état local avec l'activité quand elle est disponible
React.useEffect(() => {
if (activity && activity.data) {
setLocalData(activity.data as FreeContentData);
}
}, [activity]);

const dataChange = (key: keyof FreeContentData) => (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value.slice(0, 400); // Toujours limiter à 400 caractères
console.log('value', value);
const value = event.target.value.slice(0, 400);

// Mises à jour sur l'état local
setLocalData((prevData) => {
const newData = { ...prevData, [key]: value } as FreeContentData;
console.log('new', newData);
return newData;
});

// Mettre à jour l'activité avec les nouvelles données
updateActivity({ data: { ...localData, [key]: value } });
};

if (!activity || !user) {
Expand All @@ -69,7 +64,7 @@ const ContenuLibre = () => {
updateActivity({ displayAsUser: !activity.displayAsUser });
};

const onNext = () => {
const onNext = async () => {
save().catch(console.error);
router.push(`/admin/newportal/contenulibre/edit/3/${id}`);
};
Expand All @@ -96,7 +91,7 @@ const ContenuLibre = () => {
/>

<TextField
value={data.resume}
value={localData?.resume || ''}
onChange={dataChange('resume')}
label="Extrait votre publication"
variant="outlined"
Expand Down
Loading

0 comments on commit 9aeff9c

Please sign in to comment.