From a1a9f9d89979254b677ec55db9f41a9007d08046 Mon Sep 17 00:00:00 2001 From: Mudit Mahajan Date: Wed, 27 Dec 2023 13:37:19 +0530 Subject: [PATCH 1/4] Refactor Profile page for dynamic routing --- src/ui/app/components/navbar/index.tsx | 2 +- .../page.tsx => _packages/index.tsx} | 6 +- .../page.tsx => _services/index.tsx} | 124 ++++++++------- .../profile/[id]/{layout.tsx => page.tsx} | 144 +++++++----------- src/ui/src/utils/types.ts | 1 + 5 files changed, 121 insertions(+), 156 deletions(-) rename src/ui/app/influencer/profile/[id]/{packages/page.tsx => _packages/index.tsx} (97%) rename src/ui/app/influencer/profile/[id]/{services/page.tsx => _services/index.tsx} (88%) rename src/ui/app/influencer/profile/[id]/{layout.tsx => page.tsx} (80%) diff --git a/src/ui/app/components/navbar/index.tsx b/src/ui/app/components/navbar/index.tsx index 12dbb3fe..c97500ca 100644 --- a/src/ui/app/components/navbar/index.tsx +++ b/src/ui/app/components/navbar/index.tsx @@ -105,7 +105,7 @@ export default function Navbar({ color="inherit" sx={{ fontSize: "16px" }} onClick={() => { - window.location.href = `/influencer/profile/${currentUser?.id}}/services`; + window.location.href = `/influencer/profile/${currentUser?.id}`; }} > Profile diff --git a/src/ui/app/influencer/profile/[id]/packages/page.tsx b/src/ui/app/influencer/profile/[id]/_packages/index.tsx similarity index 97% rename from src/ui/app/influencer/profile/[id]/packages/page.tsx rename to src/ui/app/influencer/profile/[id]/_packages/index.tsx index 6b07e4fe..028b5710 100644 --- a/src/ui/app/influencer/profile/[id]/packages/page.tsx +++ b/src/ui/app/influencer/profile/[id]/_packages/index.tsx @@ -47,7 +47,7 @@ const Packages = ({ { page_number: pagination.current_page_number, page_size: pagination.current_page_size, - influencer: decodeURIComponent(params.id), + influencer: params.id, } ); if (isSuccess) { @@ -124,9 +124,7 @@ const Packages = ({ {loading ? null : ( <> - {decodeURIComponent(params.id).includes( - currentUser?.id ? currentUser?.id : "" - ) && ( + {params?.id === currentUser?.id && ( { +type ServiceProps = { + currentUser: UserType | null; + id: string; +}; + +const Services = ({ currentUser, id }: ServiceProps) => { + const [loggedInUser, setLoggedInUser] = React.useState(null); const [type, setType] = React.useState(null); - const [currentUser, setCurrentUser] = React.useState(null); const [checkedOutServices, setCheckedOutServices] = React.useState< ServiceType[] >([]); @@ -57,8 +56,8 @@ const Services = ({ { page_number: pagination.current_page_number, page_size: pagination.current_page_size, - influencer: decodeURIComponent(params.id), - status: type, + influencer: id, + status: id === loggedInUser?.id ? type : "published", } ); if (isSuccess) { @@ -127,9 +126,8 @@ const Services = ({ }, [openModal]); useEffect(() => { - if (localStorage.getItem("user")) { - setCurrentUser(JSON.parse(localStorage.getItem("user") || "{}")); - } + const user = JSON.parse(localStorage.getItem("user") || "{}"); + setLoggedInUser(user); }, []); return ( @@ -140,57 +138,57 @@ const Services = ({ }} > - - - - - - - + + + + + + )} {loading ? null : ( <> - {decodeURIComponent(params.id).includes( - currentUser?.id ? currentUser?.id : "" - ) && ( + {id === loggedInUser?.id && ( {service?.package?.name} - {service.package.influencer === currentUser?.id && ( + {service.package.influencer === loggedInUser?.id && ( - {service.package.influencer === currentUser?.id && ( + {service.package.influencer === loggedInUser?.id && ( - {service.package.influencer === currentUser?.id ? ( + {service.package.influencer === loggedInUser?.id ? ( Add to Cart @@ -472,7 +470,7 @@ const Services = ({ ]); }} disabled={ - service.package.influencer === currentUser?.id + service.package.influencer === loggedInUser?.id } > Buy Now diff --git a/src/ui/app/influencer/profile/[id]/layout.tsx b/src/ui/app/influencer/profile/[id]/page.tsx similarity index 80% rename from src/ui/app/influencer/profile/[id]/layout.tsx rename to src/ui/app/influencer/profile/[id]/page.tsx index 8064dd12..4a38ef31 100644 --- a/src/ui/app/influencer/profile/[id]/layout.tsx +++ b/src/ui/app/influencer/profile/[id]/page.tsx @@ -18,12 +18,17 @@ import { } from "@mui/material"; import dayjs from "dayjs"; import { usePathname, useRouter } from "next/navigation"; -import React, { useEffect } from "react"; +import React, { use, useEffect } from "react"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; import NextLink from "next/link"; import EditIcon from "@mui/icons-material/Edit"; import CategorySelectionModal from "@/src/components/categorySelectionModal"; -import { getServicewithCredentials } from "@/src/services/httpServices"; +import { + getService, + getServicewithCredentials, +} from "@/src/services/httpServices"; +import Services from "./_services"; +import { notification } from "@/src/components/shared/notification"; const tabs = [ { @@ -37,39 +42,24 @@ const tabs = [ ]; const ProfileLayout = ({ - children, params, }: { - children: React.ReactNode; params: { id: string; }; }) => { - const [tab, setTab] = React.useState("services"); + const [loggedInUser, setLoggedInUser] = React.useState(null); const [currentUser, setCurrentUser] = React.useState(null); - const [userAccountCategories, setUserAccountCategories] = React.useState< - AccountCategoryType[] - >([]); const [categoryOpen, setCategoryOpen] = React.useState(false); - const router = useRouter(); - const pathname = usePathname(); - const getUserCategories = async () => { - try { - const { isSuccess, data } = await getServicewithCredentials( - "account/account-category/" - ); - if (isSuccess) { - if (data?.data?.length > 0) { - localStorage.setItem("category", JSON.stringify(data?.data)); - setUserAccountCategories(data?.data); - } else if (data?.data?.length === 0) { - localStorage.removeItem("category"); - setUserAccountCategories([]); - } - } - } catch (error) { - console.error("Error during account setup check:", error); + const getUserDetails = async () => { + const { isSuccess, message, data } = await getService( + `/account/user/${params.id}/` + ); + if (isSuccess) { + setCurrentUser(data?.data); + } else { + notification(message ? message : "Error fetching user details", "error"); } }; @@ -89,37 +79,20 @@ const ProfileLayout = ({ ]; useEffect(() => { - const urlTab = pathname.split("/")[4]; // assuming the tab is the third part of the URL - if (urlTab && tabs.some((t) => t.value === urlTab)) { - if (urlTab !== tab) { - setTab(urlTab); - } - } else { - setTab(tabs[0].value); + if (params.id) { + getUserDetails(); } - }, [pathname, router]); - - useEffect(() => { - if (tab) { - router.push(`/influencer/profile/${params.id}/${tab}`); - } - }, [tab]); + }, [params.id]); useEffect(() => { if (!categoryOpen) { - getUserCategories(); + getUserDetails(); } }, [categoryOpen]); useEffect(() => { - if (localStorage.getItem("user")) { - setCurrentUser(JSON.parse(localStorage.getItem("user") || "{}")); - } - if (localStorage.getItem("category")) { - setUserAccountCategories( - JSON.parse(localStorage.getItem("category") || "{}") - ); - } + const user = JSON.parse(localStorage.getItem("user") || "{}"); + setLoggedInUser(user); }, []); return ( @@ -289,9 +262,7 @@ const ProfileLayout = ({ )} - {!decodeURIComponent(params.id).includes( - currentUser?.id ? currentUser?.id : "" - ) && ( + {params?.id !== loggedInUser?.id && ( - {`Categories (${userAccountCategories.length})`} + {`Categories (${currentUser?.twitter_account?.account_categories?.length})`} - { - setCategoryOpen(true); - }} - > - - + {params?.id === loggedInUser?.id && ( + { + setCategoryOpen(true); + }} + > + + + )} - {userAccountCategories.length === 0 && ( + {currentUser?.twitter_account?.account_categories + ?.length === 0 && ( No Categories Added )} - {userAccountCategories.map((category) => ( - - ))} + {currentUser?.twitter_account?.account_categories?.map( + (category) => ( + + ) + )} @@ -471,24 +447,14 @@ const ProfileLayout = ({ }} > {tabs.map((item) => ( - // {item.label} ))} - {children} + + + @@ -497,10 +463,12 @@ const ProfileLayout = ({ category.category.id - )} + addedCategoryObjects={currentUser?.twitter_account?.account_categories} + addedCategories={ + currentUser?.twitter_account?.account_categories?.map( + (category) => category.category.id + ) || [] + } /> ); diff --git a/src/ui/src/utils/types.ts b/src/ui/src/utils/types.ts index 8b3100a9..7b1a822b 100644 --- a/src/ui/src/utils/types.ts +++ b/src/ui/src/utils/types.ts @@ -96,6 +96,7 @@ type TwitterAccountType = { location: string | null; url: string | null; joined_at: string | null; + account_categories?: AccountCategoryType[]; }; type UserType = { From e2b4dc6d9a604a9ca1478997b718f5fe7a7a6877 Mon Sep 17 00:00:00 2001 From: Mudit Mahajan Date: Wed, 27 Dec 2023 13:50:05 +0530 Subject: [PATCH 2/4] Fix conditional rendering in Services component --- .../profile/[id]/_services/index.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/ui/app/influencer/profile/[id]/_services/index.tsx b/src/ui/app/influencer/profile/[id]/_services/index.tsx index e87c6382..8445b581 100644 --- a/src/ui/app/influencer/profile/[id]/_services/index.tsx +++ b/src/ui/app/influencer/profile/[id]/_services/index.tsx @@ -301,7 +301,7 @@ const Services = ({ currentUser, id }: ServiceProps) => { alignItems: "center", }} > - {service.package.influencer === loggedInUser?.id && ( + {service.package.influencer === loggedInUser?.id ? ( { } /> + ) : ( + + + {service?.platform_price + + " " + + service?.currency?.symbol} + + )} From 31eff4914c689efcad17d23b661ced2f7fde30ff Mon Sep 17 00:00:00 2001 From: Mudit Mahajan Date: Wed, 27 Dec 2023 14:30:18 +0530 Subject: [PATCH 3/4] Remove permission from GET request for Services --- src/api/marketplace/packages/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/marketplace/packages/views.py b/src/api/marketplace/packages/views.py index 386267c7..cd278192 100644 --- a/src/api/marketplace/packages/views.py +++ b/src/api/marketplace/packages/views.py @@ -140,6 +140,11 @@ def delete(self, request, pk): # Service class ServiceList(APIView): + def get_authenticators(self): + if self.request.method == 'POST': + return [JWTAuthentication()] + return super().get_authenticators() + def get(self, request): try: search = request.GET.get("search", "") @@ -186,7 +191,6 @@ def get(self, request): except Exception as e: return handleServerException(e) - authentication_classes = [JWTAuthentication] @swagger_auto_schema(request_body=CreateServicesSerializer) def post(self, request): try: From 1be4f61a75e16d327c01cc06d3378df107ee8dfc Mon Sep 17 00:00:00 2001 From: Mudit Mahajan Date: Thu, 28 Dec 2023 10:25:42 +0530 Subject: [PATCH 4/4] Add trusted origins for CSRF protection --- src/api/marketplace/marketplace/settings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/marketplace/marketplace/settings.py b/src/api/marketplace/marketplace/settings.py index f80778c5..a2915891 100644 --- a/src/api/marketplace/marketplace/settings.py +++ b/src/api/marketplace/marketplace/settings.py @@ -106,6 +106,14 @@ "http://127.0.0.1:3000", ] +CSRF_TRUSTED_ORIGINS = [ + "http://localhost:3000", + "https://dev.xfluencer.io", + "https://xfluencer.io", + "https://13.41.134.64", + "http://127.0.0.1:3000", +] + CORS_ALLOW_CREDENTIALS = True DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"