From 7d68bc863fbdc58d3c64d0e5aeba741869ff3a3c Mon Sep 17 00:00:00 2001 From: ElenaPavluchuk Date: Fri, 6 Feb 2026 13:57:52 +0300 Subject: [PATCH 1/4] feat-reso-164:add new resource of type post --- .../ui/CreateResourcePage.tsx | 308 +++++++++++------- src/shared/config/routeConfig/routeConfig.tsx | 14 +- 2 files changed, 200 insertions(+), 122 deletions(-) diff --git a/src/pages/CreateResourcePage/ui/CreateResourcePage.tsx b/src/pages/CreateResourcePage/ui/CreateResourcePage.tsx index 80ce096..6825bb1 100644 --- a/src/pages/CreateResourcePage/ui/CreateResourcePage.tsx +++ b/src/pages/CreateResourcePage/ui/CreateResourcePage.tsx @@ -1,60 +1,131 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import styles from "./CreateResourcePage.module.css"; -import VideoIcon from "../../../shared/ui/icons/VideoIcon"; -import ImageIcon from "../../../shared/ui/icons/ImageIcon"; -import FileIcon from "../../../shared/ui/icons/FileIcon"; -import CrossIcon from "../../../shared/ui/icons/CrossIcon"; import { useNavigate } from "react-router-dom"; import { Resource } from "../../CommunityResourcesPage/ui/constants"; +import Select from "react-select"; +import CreatableSelect from "react-select/creatable"; +import { MultiValue } from "react-select"; +import { useUser } from "../../../shared/lib/customHooks/useUser"; +import axios from "axios"; interface CreateResourcePageProps { addResource?: (newResource: Resource) => void; } +type ResourceType = "post" | "youtube" | ""; +type Visibility = "everyone" | "members" | "mentors"; + export const CreateResourcePage: React.FC = ({ addResource, }) => { - const [title, setTitle] = useState(""); - const [description, setDescription] = useState(""); - const [file, setFile] = useState(null); - const [fullInfo, setFullInfo] = useState(""); - const [selectedTag, setSelectedTag] = useState(null); - - const tags = ["Documents", "Video", "Links", "Posts"]; + const userIdFromLocalStorage = localStorage.getItem("userId") + ? Number(localStorage.getItem("userId")) + : null; + const { user } = useUser(userIdFromLocalStorage); + const [resourceType, setResourceType] = useState(""); + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [tags, setTags] = useState< + MultiValue<{ value: string; label: string }> + >([]); + const [selectedTags, setSelectedTags] = useState< + MultiValue<{ value: string; label: string }> + >([]); + const [visibility, setVisibility] = useState("everyone"); + const [isMentor, setIsMentor] = useState(false); + const [errors, setErrors] = useState>({}); const navigate = useNavigate(); - const handleTagClick = (tag: string) => { - setSelectedTag(tag); - }; - - const handleFileChange = (e: React.ChangeEvent) => { - if (e.target.files && e.target.files[0]) { - setFile(e.target.files[0]); + const resourceTypeOptions = [ + { value: "post", label: "post" }, + { value: "youtube video", label: "youtube video" }, + ]; + + const visibilityOptions: { + value: Visibility; + label: string; + forMentorOnly?: boolean; + }[] = [ + { value: "everyone", label: "Everyone" }, + { value: "members", label: "Members only" }, + { value: "mentors", label: "Mentors only", forMentorOnly: isMentor }, + ]; + + useEffect(() => { + if (user) { + setIsMentor( + user?.roles?.filter( + (role: { role_id: number; role_name: string }) => + role.role_name === "mentor", + ).length > 0, + ); } + }, [user]); + + useEffect(() => { + const fetchTags = async () => { + try { + const response = await axios.get(`${import.meta.env.VITE_DEVAPI}tags`, { + withCredentials: true, + }); + + const formattedTags = response?.data?.tags.map((tag: string) => ({ + value: tag, + label: tag, + })); + + setTags(formattedTags); + } catch (error) { + console.error("Error fetching tags:", error); + } + }; + + fetchTags(); + }, []); + + const handleTagChange = ( + selectedOptions: MultiValue<{ value: string; label: string }>, + ) => { + setSelectedTags(selectedOptions || []); }; - const handleFileClick = (accept: string) => { - const input = document.getElementById("file") as HTMLInputElement; - if (input) { - input.setAttribute("accept", accept); - input.click(); + const validate = () => { + const validateErrors: Record = {}; + + if (!resourceType) + validateErrors.resourceType = "Resource type is required"; + if (!title.trim()) { + validateErrors.title = "Title is required"; + } else if (title.trim().length < 1 || title.trim().length > 100) { + validateErrors.title = "Title must be between 1 and 100 characters"; + } + if (resourceType === "post" && !description.trim()) { + validateErrors.description = "Description is required for posts"; } + if (selectedTags.length === 0) + validateErrors.selectedTags = "Please add at least one tag"; + + setErrors(validateErrors); + return Object.keys(validateErrors).length === 0; }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - if (!selectedTag) { - alert("Please select a tag for the resource."); - return; - } + if (!validate()) return; + + // if (!selectedTag) { + // alert("Please select a tag for the resource."); + // return; + // } const newResource = { id: Date.now(), title, description, - file, - fullInfo, - tags: [selectedTag], + // file, + // fullInfo, + // tags: [selectedTag], + tags: selectedTags.map((tag) => tag.value), }; if (addResource) { @@ -65,100 +136,107 @@ export const CreateResourcePage: React.FC = ({ setTitle(""); setDescription(""); - setFile(null); - setFullInfo(""); - setSelectedTag(null); + // setFile(null); + // setFullInfo(""); + // setSelectedTag(null); }; return (
-

Create a New Resource

+

Add new resource

- setTitle(e.target.value)} - className={styles.input} - required - /> - setDescription(e.target.value)} - className={styles.input} - required - /> - - - -
- - -