From d4c22eed4ab3fe7193d4a753664610cce766531d Mon Sep 17 00:00:00 2001 From: ElenaPavluchuk Date: Tue, 3 Mar 2026 11:11:02 +0300 Subject: [PATCH 1/3] feat-reso-171:resource page --- src/pages/ResourcePage/index.ts | 3 +++ src/pages/ResourcePage/ui/ResourcePage.css | 0 src/pages/ResourcePage/ui/ResourcePage.tsx | 3 +++ src/shared/config/routeConfig/routeConfig.tsx | 7 +++++++ 4 files changed, 13 insertions(+) create mode 100644 src/pages/ResourcePage/index.ts create mode 100644 src/pages/ResourcePage/ui/ResourcePage.css create mode 100644 src/pages/ResourcePage/ui/ResourcePage.tsx diff --git a/src/pages/ResourcePage/index.ts b/src/pages/ResourcePage/index.ts new file mode 100644 index 0000000..50470cf --- /dev/null +++ b/src/pages/ResourcePage/index.ts @@ -0,0 +1,3 @@ +import ResourcePage from "./ui/ResourcePage"; + +export { ResourcePage }; diff --git a/src/pages/ResourcePage/ui/ResourcePage.css b/src/pages/ResourcePage/ui/ResourcePage.css new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/ResourcePage/ui/ResourcePage.tsx b/src/pages/ResourcePage/ui/ResourcePage.tsx new file mode 100644 index 0000000..9c08520 --- /dev/null +++ b/src/pages/ResourcePage/ui/ResourcePage.tsx @@ -0,0 +1,3 @@ +export default function ResourcePage() { + return
ResourcePage
; +} diff --git a/src/shared/config/routeConfig/routeConfig.tsx b/src/shared/config/routeConfig/routeConfig.tsx index 99164fa..fc2977c 100644 --- a/src/shared/config/routeConfig/routeConfig.tsx +++ b/src/shared/config/routeConfig/routeConfig.tsx @@ -20,6 +20,7 @@ import TandC from "../../../pages/TandC"; import { CreateApplicationMentorPage } from "../../../pages/CreateApplicationMentorPage"; import { MentorUserProfilePage } from "../../../pages/MentorUserProfilePage"; import { AuthDiscordCallbackPage } from "../../../pages/AuthDiscordCallbackPage"; +import { ResourcePage } from "../../../pages/ResourcePage"; export enum AppRoutes { MAIN = "main", @@ -42,6 +43,7 @@ export enum AppRoutes { CREATE_APPLICATION_MENTOR = "create_application_mentor", MENTOR_USER_PROFILE = "mentor_user_profile/:id", AUTH_DISCORD_CALLBACK = "auth/discord/callback", + RESOURCE = "resource", } export const RoutePath: Record = { @@ -65,6 +67,7 @@ export const RoutePath: Record = { [AppRoutes.CREATE_APPLICATION_MENTOR]: "/create_application_mentor", [AppRoutes.MENTOR_USER_PROFILE]: "/mentor_user_profile/:id", [AppRoutes.AUTH_DISCORD_CALLBACK]: "/auth/discord/callback", + [AppRoutes.RESOURCE]: "/resource", }; export const routeConfig: Record = { @@ -148,4 +151,8 @@ export const routeConfig: Record = { path: RoutePath[AppRoutes.AUTH_DISCORD_CALLBACK], element: , }, + [AppRoutes.RESOURCE]: { + path: RoutePath.resource, + element: , + }, }; From b73e4d495c20b60cbce3f23a0c7b1e56e8ab67b3 Mon Sep 17 00:00:00 2001 From: ElenaPavluchuk Date: Wed, 4 Mar 2026 20:04:37 +0300 Subject: [PATCH 2/3] feat-reso-171:add access check --- src/pages/ResourcePage/ui/ResourcePage.tsx | 75 +++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/pages/ResourcePage/ui/ResourcePage.tsx b/src/pages/ResourcePage/ui/ResourcePage.tsx index 9c08520..5f4c709 100644 --- a/src/pages/ResourcePage/ui/ResourcePage.tsx +++ b/src/pages/ResourcePage/ui/ResourcePage.tsx @@ -1,3 +1,76 @@ +import { useState, useEffect } from "react"; +import { useUser } from "../../../shared/lib/customHooks/useUser"; +import type { UserRole } from "../../../app/types/global"; + +type Audience = "public" | "mentor" | "member"; + +type Resource = { + id: string; + title: string; + type: string; + audience: Audience[]; + description: string; + tags: string[] | null; +}; + export default function ResourcePage() { - return
ResourcePage
; + const userIdFromLocalStorage = localStorage.getItem("userId") + ? Number(localStorage.getItem("userId")) + : null; + const { user } = useUser(userIdFromLocalStorage); + const [resource, setResource] = useState(null); + + useEffect(() => { + // TODO: fetch resource from API + const fetchedResource: Resource = { + id: crypto.randomUUID(), + title: "Test resource", + type: "post", + audience: ["mentor"], + description: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry", + tags: null, + }; + + setResource(fetchedResource); + }, []); + + const hasAccess = () => { + if (!resource) return false; + + if (resource.audience.includes("public")) { + return true; + } + + if (!user) { + return false; + } + + const userRoles = user.roles.map((r) => r.role_name); + if (userRoles.includes("admin")) return true; + + return resource.audience.some((requiredRole) => { + return userRoles.includes(requiredRole as UserRole); + }); + }; + + if (!resource) { + return
Resource not found
; + } + + if (!hasAccess()) { + return ( +
+

You don't have access to view this page

+
+ ); + } + + return ( +
+
+

Resource Page

+
+
+ ); } From 76d000a05b9e9944ebecdb2754b3a35d13bc69dc Mon Sep 17 00:00:00 2001 From: ElenaPavluchuk Date: Thu, 12 Mar 2026 14:44:23 +0300 Subject: [PATCH 3/3] feat-reso-171:add resource page design --- src/pages/ResourcePage/ui/ResourcePage.css | 0 .../ResourcePage/ui/ResourcePage.module.css | 54 +++++++++++++++++++ src/pages/ResourcePage/ui/ResourcePage.tsx | 36 +++++++++++-- 3 files changed, 85 insertions(+), 5 deletions(-) delete mode 100644 src/pages/ResourcePage/ui/ResourcePage.css create mode 100644 src/pages/ResourcePage/ui/ResourcePage.module.css diff --git a/src/pages/ResourcePage/ui/ResourcePage.css b/src/pages/ResourcePage/ui/ResourcePage.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/pages/ResourcePage/ui/ResourcePage.module.css b/src/pages/ResourcePage/ui/ResourcePage.module.css new file mode 100644 index 0000000..4a8eb94 --- /dev/null +++ b/src/pages/ResourcePage/ui/ResourcePage.module.css @@ -0,0 +1,54 @@ +.tagsContainer { + position: relative; + display: flex; + flex-wrap: wrap; + gap: 16px 0; + align-items: center; + background: rgba(250, 103, 115, 0.15); + backdrop-filter: blur(30); + border-radius: 30px; + box-shadow: 0px 6px 10px 0px #fe444440; + padding: 24px; + overflow: hidden; +} + +.tagsContainer::before { + content: ""; + position: absolute; + inset: 0; + background-color: rgba(250, 103, 115, 0.2); + border-radius: inherit; + filter: blur(30px); + z-index: -1; + box-shadow: 0px 6px 10px 0px #fe444440; +} + +.tags { + position: relative; + display: inline-block; + background-color: #fef7f8; + padding: 10px 16px; + min-width: 60px; + text-align: center; + border-radius: 100px; + z-index: 0; +} + +.tags::before { + content: ""; + position: absolute; + inset: 0; + padding: 1px; + border-radius: inherit; + background: linear-gradient( + 90deg, + rgba(255, 55, 127, 1) 0%, + rgba(255, 212, 130, 1) 85% + ); + mask: + linear-gradient(90deg, #fff 0%, #fff 100%) content-box, + linear-gradient(90deg, #fff 0%, #fff 100%); + -webkit-mask-composite: destination-out; + mask-composite: exclude; + z-index: -1; +} diff --git a/src/pages/ResourcePage/ui/ResourcePage.tsx b/src/pages/ResourcePage/ui/ResourcePage.tsx index 5f4c709..b912ed2 100644 --- a/src/pages/ResourcePage/ui/ResourcePage.tsx +++ b/src/pages/ResourcePage/ui/ResourcePage.tsx @@ -1,6 +1,9 @@ import { useState, useEffect } from "react"; import { useUser } from "../../../shared/lib/customHooks/useUser"; import type { UserRole } from "../../../app/types/global"; +import style from "./ResourcePage.module.css"; +import Navbar from "../../../shared/ui/Navbar/Navbar"; +import Footer from "../../../shared/ui/Footer/Footer"; type Audience = "public" | "mentor" | "member"; @@ -29,7 +32,7 @@ export default function ResourcePage() { audience: ["mentor"], description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", - tags: null, + tags: ["react", "javascript"], }; setResource(fetchedResource); @@ -55,7 +58,7 @@ export default function ResourcePage() { }; if (!resource) { - return
Resource not found
; + return
Resource loading
; } if (!hasAccess()) { @@ -67,10 +70,33 @@ export default function ResourcePage() { } return ( -
-
-

Resource Page

+
+ +
+

{resource?.title}

+
+ +
+
+

+ {resource?.description} +

+
+ +
+ {(resource.tags ?? []).map((tag) => ( + + {tag} + + ))} +
+
); }