mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
feat(Choose passions): Can now choose passion
Todo : fetch userData in useEffect and using userData for userProfile
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
useCheckbox,
|
||||||
|
Text,
|
||||||
|
Flex,
|
||||||
|
chakra,
|
||||||
|
Box,
|
||||||
|
Tag,
|
||||||
|
TagLeftIcon,
|
||||||
|
TagLabel,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
|
||||||
|
import { IoAdd, IoRemove } from "react-icons/io5";
|
||||||
|
|
||||||
|
export default function CustomCheckbox(props) {
|
||||||
|
const { text, checked, value } = props;
|
||||||
|
const { state, getInputProps, getCheckboxProps, getLabelProps, htmlProps } =
|
||||||
|
useCheckbox(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<chakra.label
|
||||||
|
// colorScheme={"purple"}
|
||||||
|
variant={state.isChecked ? "solid" : "outline"}
|
||||||
|
cursor="pointer"
|
||||||
|
{...htmlProps}
|
||||||
|
>
|
||||||
|
<input {...getInputProps()} hidden />
|
||||||
|
{state.isChecked ? (
|
||||||
|
<Tag
|
||||||
|
{...getCheckboxProps()}
|
||||||
|
colorScheme={"purple"}
|
||||||
|
{...getLabelProps()}
|
||||||
|
>
|
||||||
|
<TagLeftIcon as={IoRemove} />
|
||||||
|
<TagLabel>{text}</TagLabel>
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag
|
||||||
|
{...getCheckboxProps()}
|
||||||
|
colorScheme={"purple"}
|
||||||
|
variant={"outline"}
|
||||||
|
{...getLabelProps()}
|
||||||
|
>
|
||||||
|
<TagLeftIcon as={IoAdd} />
|
||||||
|
<TagLabel>{text}</TagLabel>
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</chakra.label>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
|
Text,
|
||||||
|
useCheckbox,
|
||||||
|
useCheckboxGroup,
|
||||||
|
useDisclosure,
|
||||||
|
useToast,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { RiEditBoxLine } from "react-icons/ri";
|
||||||
|
import CustomCheckbox from "./CustomCheckbox";
|
||||||
|
|
||||||
|
export default function ModalChoosePassion(props) {
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
const { user, passions } = props;
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const { value, getCheckboxProps } = useCheckboxGroup({
|
||||||
|
defaultValue: user.PassionID,
|
||||||
|
});
|
||||||
|
|
||||||
|
const savePassions = (PassionID) => {
|
||||||
|
const options = {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ PassionID }),
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(`/api/users/${user.id}`, options)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
toast({
|
||||||
|
title: "Centres d'intérêts mis à jour",
|
||||||
|
status: "success",
|
||||||
|
duration: 9000,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
onClose();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
colorScheme={"purple"}
|
||||||
|
onClick={onOpen}
|
||||||
|
leftIcon={<RiEditBoxLine />}
|
||||||
|
>
|
||||||
|
Choisir les centres d'intérèts
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
blockScrollOnMount={false}
|
||||||
|
size={"4xl"}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
scrollBehavior={"inside"}
|
||||||
|
>
|
||||||
|
<ModalOverlay />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader>Choix des centres d'intérèts</ModalHeader>
|
||||||
|
<ModalCloseButton />
|
||||||
|
<ModalBody>
|
||||||
|
<Flex gap={"1rem"} flexWrap="wrap">
|
||||||
|
{passions !== null ? (
|
||||||
|
passions.map((passion, index) => {
|
||||||
|
return (
|
||||||
|
<CustomCheckbox
|
||||||
|
{...getCheckboxProps({ value: passion.id })}
|
||||||
|
key={passion.id}
|
||||||
|
text={passion.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<Button
|
||||||
|
colorScheme="purple"
|
||||||
|
mr={3}
|
||||||
|
onClick={() => savePassions(value)}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Grid,
|
||||||
|
GridItem,
|
||||||
|
Image,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
|
useDisclosure,
|
||||||
|
useToast,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { RiEditBoxLine } from "react-icons/ri";
|
||||||
|
|
||||||
|
export default function ModalModifyImages(props) {
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
const { images, user, userData, setUserData } = props;
|
||||||
|
const [listImage, setlistImage] = useState(images);
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const uploadImage = async (file) => {
|
||||||
|
const body = new FormData();
|
||||||
|
body.append("file", file);
|
||||||
|
const imagePostOptions = {
|
||||||
|
method: "POST",
|
||||||
|
body,
|
||||||
|
};
|
||||||
|
|
||||||
|
const imagePatchOptions = {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
images: [...listImage, `imageUsers/${file.name}`],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(`/api/file/uploadFile`, imagePostOptions)
|
||||||
|
.then((res) => {
|
||||||
|
fetch(`/api/users/${user.id}`, imagePatchOptions)
|
||||||
|
.then((res) => {
|
||||||
|
toast({
|
||||||
|
title: `Ajout d'image effectué`,
|
||||||
|
status: "success",
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
setlistImage([...listImage, `imageUsers/${file.name}`]);
|
||||||
|
// router.reload();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
toast({
|
||||||
|
title: `Erreur lors de l'ajout des images`,
|
||||||
|
status: "error",
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast({
|
||||||
|
title: `Erreur lors de l'ajout des images`,
|
||||||
|
status: "error",
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteImage = async (fileName) => {
|
||||||
|
let newListImage = listImage;
|
||||||
|
const index = newListImage.indexOf(fileName);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
newListImage.splice(index, 1);
|
||||||
|
setlistImage([...newListImage]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageDeleteOptions = {
|
||||||
|
method: "DELETE",
|
||||||
|
body: JSON.stringify({ fileName: fileName.split("/").pop() }),
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(`/api/file/deleteFile`, imageDeleteOptions).then((res) => {
|
||||||
|
const imagePatchOptions = {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
images: [...listImage],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
fetch(`/api/users/${user.id}`, imagePatchOptions)
|
||||||
|
.then((res) => {
|
||||||
|
toast({
|
||||||
|
title: `Suppression d'image effectué`,
|
||||||
|
status: "success",
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast({
|
||||||
|
title: `Erreur lors de la suppression des images`,
|
||||||
|
status: "error",
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
colorScheme={"purple"}
|
||||||
|
onClick={onOpen}
|
||||||
|
leftIcon={<RiEditBoxLine />}
|
||||||
|
>
|
||||||
|
Modifier les images
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
blockScrollOnMount={false}
|
||||||
|
size={"4xl"}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
scrollBehavior={"inside"}
|
||||||
|
>
|
||||||
|
<ModalOverlay />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader>Modification des images</ModalHeader>
|
||||||
|
<ModalCloseButton />
|
||||||
|
<ModalBody>
|
||||||
|
<Grid
|
||||||
|
templateColumns={`repeat(${listImage.length + 1}, 1fr)`}
|
||||||
|
gap={5}
|
||||||
|
>
|
||||||
|
{listImage.map((image, index) => (
|
||||||
|
<GridItem key={index}>
|
||||||
|
<Flex direction={"column"} gap={"1rem"}>
|
||||||
|
<Image src={image} />
|
||||||
|
<Button
|
||||||
|
id={"" + index}
|
||||||
|
colorScheme={"red"}
|
||||||
|
onClick={(e) => {
|
||||||
|
deleteImage(`${listImage[index]}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Supprimer l'image
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</GridItem>
|
||||||
|
))}
|
||||||
|
{listImage.length < 5 ? (
|
||||||
|
<GridItem width={"100%"}>
|
||||||
|
<Input
|
||||||
|
type={"file"}
|
||||||
|
height={"100%"}
|
||||||
|
accept={"image/png, image/jpeg, image/webp"}
|
||||||
|
onInput={({ target }) => {
|
||||||
|
const date = new Date();
|
||||||
|
const time = date.getTime();
|
||||||
|
|
||||||
|
const file = target.files[0];
|
||||||
|
const extension = file.name.split(".").pop();
|
||||||
|
const newFile = new File(
|
||||||
|
[file],
|
||||||
|
`${user.id}_${time}.${extension}`,
|
||||||
|
{
|
||||||
|
type: file.type,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
uploadImage(newFile);
|
||||||
|
}}
|
||||||
|
></Input>
|
||||||
|
</GridItem>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<Button
|
||||||
|
colorScheme="purple"
|
||||||
|
mr={3}
|
||||||
|
onClick={(e) => {
|
||||||
|
setUserData({
|
||||||
|
...userData,
|
||||||
|
images: [...listImage],
|
||||||
|
});
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Flex, Tag } from "@chakra-ui/react";
|
||||||
|
|
||||||
|
export default function ProfileBadgeList(props) {
|
||||||
|
const { passions, userPassions } = props;
|
||||||
|
return (
|
||||||
|
<Flex gap={"0.5rem"} mt={"1vh"} flexWrap="wrap">
|
||||||
|
{userPassions.map((idPassion, index) => (
|
||||||
|
<Tag key={index} colorScheme={"purple"}>
|
||||||
|
{passions !== null && passions !== undefined
|
||||||
|
? passions.find((element) => element.id === idPassion).name
|
||||||
|
: ""}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
+28
-16
@@ -23,21 +23,22 @@ import {
|
|||||||
RadioGroup,
|
RadioGroup,
|
||||||
Text,
|
Text,
|
||||||
useToast,
|
useToast,
|
||||||
|
VStack,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
|
|
||||||
import ModalModifyImages from "@/components/layout/user_profile/ModalModifyImages";
|
import ModalModifyImages from "@/components/layout/user_profile/ModalModifyImages";
|
||||||
import ModalChoosePassion from "@/components/layout/user_profile/ModalChoosePassion";
|
import ModalChoosePassion from "@/components/layout/user_profile/ModalChoosePassion";
|
||||||
import ProfileBadgeList from "@/components/layout/user_profile/ProfileBadgeList";
|
import ProfileTagList from "@/components/layout/user_profile/ProfileTagList";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
|
||||||
export default function UserProfile() {
|
export default function UserProfile() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [passions, setPassions] = useState(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -45,6 +46,18 @@ export default function UserProfile() {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm();
|
} = useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`/api/passions`)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
setPassions([...data]);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
// faire un useEffect ou je fetch user
|
||||||
|
|
||||||
const [userData, setUserData] = useState({});
|
const [userData, setUserData] = useState({});
|
||||||
|
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
@@ -86,7 +99,7 @@ export default function UserProfile() {
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
toast({
|
toast({
|
||||||
position:'top',
|
position: "top",
|
||||||
title: `Modifications effectuées`,
|
title: `Modifications effectuées`,
|
||||||
status: "success",
|
status: "success",
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
@@ -97,7 +110,7 @@ export default function UserProfile() {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
toast({
|
toast({
|
||||||
title: `Erreur lors de l'envoi des modifications`,
|
title: `Erreur lors de l'envoi des modifications`,
|
||||||
position :'top',
|
position: "top",
|
||||||
status: "error",
|
status: "error",
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
});
|
});
|
||||||
@@ -310,16 +323,15 @@ export default function UserProfile() {
|
|||||||
<FormLabel as={"legend"} htmlFor={"passion"}>
|
<FormLabel as={"legend"} htmlFor={"passion"}>
|
||||||
Centre d'intéret :
|
Centre d'intéret :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<Controller
|
<VStack gap={"1rem"} align="start">
|
||||||
name={"passion"}
|
<ProfileTagList
|
||||||
control={control}
|
userPassions={
|
||||||
render={({ field }) => (
|
user.PassionID !== undefined ? user.PassionID : []
|
||||||
<>
|
}
|
||||||
<ProfileBadgeList passions={user.passion !== undefined ? user.passion : []}/>
|
passions={passions}
|
||||||
<ModalChoosePassion user={user}/>
|
/>
|
||||||
</>
|
<ModalChoosePassion user={user} passions={passions} />
|
||||||
)}
|
</VStack>
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Divider colorScheme={"purple"} />
|
<Divider colorScheme={"purple"} />
|
||||||
@@ -403,7 +415,7 @@ export default function UserProfile() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
colorScheme={"purple"}
|
colorScheme={"purple"}
|
||||||
variant='outline'
|
variant="outline"
|
||||||
onClick={() => router.push("/dashboard")}
|
onClick={() => router.push("/dashboard")}
|
||||||
>
|
>
|
||||||
Retour
|
Retour
|
||||||
|
|||||||
@@ -1050,14 +1050,9 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"glob" "7.1.7"
|
"glob" "7.1.7"
|
||||||
|
|
||||||
"@next/swc-linux-x64-gnu@13.2.3":
|
"@next/swc-win32-x64-msvc@13.2.3":
|
||||||
"integrity" "sha512-w5MyxPknVvC9LVnMenAYMXMx4KxPwXuJRMQFvY71uXg68n7cvcas85U5zkdrbmuZ+JvsO5SIG8k36/6X3nUhmQ=="
|
"integrity" "sha512-aLG2MaFs4y7IwaMTosz2r4mVbqRyCnMoFqOcmfTi7/mAS+G4IMH0vJp4oLdbshqiVoiVuKrAfqtXj55/m7Qu1Q=="
|
||||||
"resolved" "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.3.tgz"
|
"resolved" "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.3.tgz"
|
||||||
"version" "13.2.3"
|
|
||||||
|
|
||||||
"@next/swc-linux-x64-musl@13.2.3":
|
|
||||||
"integrity" "sha512-CTeelh8OzSOVqpzMFMFnVRJIFAFQoTsI9RmVJWW/92S4xfECGcOzgsX37CZ8K982WHRzKU7exeh7vYdG/Eh4CA=="
|
|
||||||
"resolved" "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.3.tgz"
|
|
||||||
"version" "13.2.3"
|
"version" "13.2.3"
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.5":
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
|
|||||||
Reference in New Issue
Block a user