From 08081b61140cfcf296c103b5f6517dfd6a7660f3 Mon Sep 17 00:00:00 2001 From: bacpactech Date: Mon, 28 Oct 2024 12:51:42 +0530 Subject: [PATCH 1/5] added connections UI WIP profile --- src/app/(withLayout)/connections/page.tsx | 42 +++- src/app/(withLayout)/profile/page.tsx | 55 +++++ src/app/(withLayout)/timeline/page.tsx | 4 +- src/assets/badge.svg | 10 + src/components/Connections/FindPeople.tsx | 4 + src/components/Timeline/Modal.tsx | 2 +- .../Timeline/Modals/EditProfileModal.tsx | 218 +++++++++++------- src/components/Timeline/UserListItem.tsx | 59 +++-- src/components/atoms/Card/index.tsx | 10 +- .../atoms/SelectDropdown/SelectDropdown.tsx | 2 +- .../molecules/NavbarUniversityItem/index.tsx | 29 ++- src/components/molecules/Tabs/FindPeople.tsx | 92 ++++++++ src/components/molecules/Tabs/Followers.tsx | 63 +++++ src/components/molecules/Tabs/Following.tsx | 62 +++++ src/components/molecules/Tabs/index.tsx | 14 +- src/components/organism/Login/LoginBox.tsx | 5 +- .../Register/formContainer/FormContainer.tsx | 2 +- src/components/organisms/LeftNavbar/index.tsx | 25 +- .../organisms/ProfileCard/index.tsx | 187 +++++++++++++++ .../organisms/UserPostContainer/index.tsx | 2 +- src/services/api-Client.ts | 16 +- src/services/auth.ts | 2 +- src/services/connection.ts | 1 + src/services/universitySearch.tsx | 2 +- src/services/user.ts | 26 ++- src/store/userProfileSlice/userProfileType.ts | 1 + src/types/Connections/index.ts | 87 +++++++ src/types/constants.ts | 1 + tailwind.config.js | 2 + 29 files changed, 864 insertions(+), 161 deletions(-) create mode 100644 src/app/(withLayout)/profile/page.tsx create mode 100644 src/assets/badge.svg create mode 100644 src/components/molecules/Tabs/FindPeople.tsx create mode 100644 src/components/molecules/Tabs/Followers.tsx create mode 100644 src/components/molecules/Tabs/Following.tsx create mode 100644 src/components/organisms/ProfileCard/index.tsx create mode 100644 src/types/Connections/index.ts diff --git a/src/app/(withLayout)/connections/page.tsx b/src/app/(withLayout)/connections/page.tsx index 6ee8060c..d6dac8b9 100644 --- a/src/app/(withLayout)/connections/page.tsx +++ b/src/app/(withLayout)/connections/page.tsx @@ -1,5 +1,43 @@ -import React from 'react' +'use client' +import Card from '@/components/atoms/Card' +import Tabs from '@/components/molecules/Tabs' +import FindPeople from '@/components/molecules/Tabs/FindPeople' +import Followers from '@/components/molecules/Tabs/Followers' +import Following from '@/components/molecules/Tabs/Following' +import { useUniStore } from '@/store/store' +import React, { useMemo, useRef } from 'react' export default function ConnectionPage() { - return
ConnectionPage
+ const { userProfileData } = useUniStore() + + const userFollowingIDs = useMemo(() => { + return userProfileData?.following?.map((following: { userId: string }) => following.userId) + }, [userProfileData]) + + const userFollowerIDs = useMemo(() => { + return userProfileData?.followers?.map((followers: { userId: string }) => followers.userId) + }, [userProfileData]) + + const tabs = [ + { + label: 'Find People', + content: , + }, + { + label: `Following`, + content: , + }, + { + label: `Follower`, + content: , + }, + ] + + return ( +
+ + + +
+ ) } diff --git a/src/app/(withLayout)/profile/page.tsx b/src/app/(withLayout)/profile/page.tsx new file mode 100644 index 00000000..e1d8d9ba --- /dev/null +++ b/src/app/(withLayout)/profile/page.tsx @@ -0,0 +1,55 @@ +'use client' +import { UserProfileCard } from '@/components/organisms/ProfileCard' +import Modal from '@/components/Timeline/Modal' +import ConnectionsModal from '@/components/Timeline/Modals/ConnectionsModal' +import EditProfileModal from '@/components/Timeline/Modals/EditProfileModal' +import ProfileCard from '@/components/Timeline/ProfileCard' +import { useUniStore } from '@/store/store' +import { ModalContentType } from '@/types/global' +import React, { useState } from 'react' + +export default function Profile() { + const [isModalOpen, setIsModalOpen] = useState(false) + const [modalContentType, setModalContentType] = useState() + const { userData, userProfileData } = useUniStore() + const modalContent = (modalContentType: string) => { + switch (modalContentType) { + case 'EditProfileModal': + return + case 'ConnectionsModal': + return + default: + return null + } + } + const { bio, university_name, followers, following, study_year, major, phone_number, dob, degree, country } = userProfileData + const { firstName, lastName, email } = userData + return ( +
+ setIsModalOpen(false)}> + {modalContentType && modalContent(modalContentType)} + + +
+ ) +} diff --git a/src/app/(withLayout)/timeline/page.tsx b/src/app/(withLayout)/timeline/page.tsx index c3ec3ec5..2b28c065 100644 --- a/src/app/(withLayout)/timeline/page.tsx +++ b/src/app/(withLayout)/timeline/page.tsx @@ -5,9 +5,9 @@ import React from 'react' export default function Timeline() { return ( - <> +
- +
) } diff --git a/src/assets/badge.svg b/src/assets/badge.svg new file mode 100644 index 00000000..db6aadbe --- /dev/null +++ b/src/assets/badge.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/components/Connections/FindPeople.tsx b/src/components/Connections/FindPeople.tsx index 1a3406e7..8844a399 100644 --- a/src/components/Connections/FindPeople.tsx +++ b/src/components/Connections/FindPeople.tsx @@ -7,6 +7,7 @@ import { useGetAllUserWithProfileData, useGetUserFollow, useGetUserFollowers } f import UserListItemSkeleton from './UserListItemSkeleton' import { useUniStore } from '@/store/store' import { FindUsers, FollowingItemProps } from '@/types/constants' +import { useUsersProfileForConnections } from '@/services/user' type ContentType = 'Find People' | 'Following' | 'Followers' @@ -71,6 +72,9 @@ const FindPeople = ({ contentDivStyle }: { contentDivStyle?: string }) => { const [content, setContent] = useState('Find People') const [name, setName] = useState('') const { userProfileData } = useUniStore() + const [page, setPage] = useState(0) + const { data: userProfilesData } = useUsersProfileForConnections(name, page, false) + const userFollowingIDs = userProfileData && userProfileData?.following?.map((following) => following.userId) const { data: allUserData, isFetching } = useGetAllUserWithProfileData(name, content == 'Find People') const { data: userFollow, isFetching: isFollowingLoading } = useGetUserFollow(name, content == 'Following') diff --git a/src/components/Timeline/Modal.tsx b/src/components/Timeline/Modal.tsx index 1d6545d7..8256f254 100644 --- a/src/components/Timeline/Modal.tsx +++ b/src/components/Timeline/Modal.tsx @@ -35,7 +35,7 @@ const Modal: React.FC = ({ isOpen, onClose, children }) => { <> {showModal && (
-
+
+
) diff --git a/src/components/Timeline/UserListItem.tsx b/src/components/Timeline/UserListItem.tsx index aa0329f4..3eb3a6a2 100644 --- a/src/components/Timeline/UserListItem.tsx +++ b/src/components/Timeline/UserListItem.tsx @@ -1,9 +1,8 @@ -/* eslint-disable @next/next/no-img-element */ import React from 'react' -import { SlOptionsVertical } from 'react-icons/sl' -import { Popover, PopoverContent, PopoverTrigger } from '../ui/Popover' import { useToggleFollow } from '@/services/connection' import { useCreateUserChat } from '@/services/Messages' +import LoginButtons from '../atoms/LoginButtons' +import avatar from '@assets/avatar.svg' interface FollowingItemProps { firstName: string @@ -37,39 +36,33 @@ const UserListItem: React.FC = ({ const { mutate: toggleFollow } = useToggleFollow(type) const { mutate: createUserChat } = useCreateUserChat() + const handleFollowClick = () => { + if (!userFollowingIDs?.includes(id)) { + toggleFollow(id) + } + } + return ( -
- {imageUrl ? ( - {firstName} - ) : ( -
- )} -
-

- {firstName} {lastName} -

-

{university}

-

- {study_year} - {degree} - {major} -

-
- - {study_year ? study_year + 'Yr.' : ''} - - {occupation && {occupation}} - {degree} - {major} - {/* {tags?.map((tag, index) => ( - - {tag.label} - - ))} */} +
+
+ {firstName} +
+

+ {firstName} {lastName} +

+ {university &&

{university}

} + +

+ {study_year} {degree} {major} +

+
- + + {userFollowingIDs?.includes(id) ? 'View Profile' : 'Follow'} + + {/* @@ -80,7 +73,7 @@ const UserListItem: React.FC = ({

toggleFollow(id)}>{userFollowingIDs?.includes(id) ? 'Un-Follow' : 'Follow'}

)} -
+
*/}
) diff --git a/src/components/atoms/Card/index.tsx b/src/components/atoms/Card/index.tsx index 6c5b0e66..d625a90e 100644 --- a/src/components/atoms/Card/index.tsx +++ b/src/components/atoms/Card/index.tsx @@ -3,11 +3,13 @@ import React, { ReactNode, HTMLAttributes } from 'react' interface TitleProps extends HTMLAttributes { children: ReactNode } - -export default function Card({ children, className = '', ...rest }: TitleProps) { +const Card = React.forwardRef((props: TitleProps, ref) => { + const { children, className = '', ...rest } = props return ( -
+
{children}
) -} +}) + +export default Card diff --git a/src/components/atoms/SelectDropdown/SelectDropdown.tsx b/src/components/atoms/SelectDropdown/SelectDropdown.tsx index dc3279e1..16a53c19 100644 --- a/src/components/atoms/SelectDropdown/SelectDropdown.tsx +++ b/src/components/atoms/SelectDropdown/SelectDropdown.tsx @@ -79,7 +79,7 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search = {search && ( - if (SubscribedData?.community.length === 0) return

Join Your University

+ // if (SubscribedData?.community.length === 0) + // return ( + //
+ // + // Add Your University + // {' '} + //
+ // ) return ( <> + {SubscribedData?.community.length === 0 && ( +
+ + Add Your University + {' '} +
+ )} {SubscribedData?.community.map((community, index) => { return (
@@ -205,7 +220,7 @@ export default function NavbarUniversityItem({ setActiveMenu }: any) {
-
+
- + + {SubscribedData?.community.length !== 0 ? ( + + ) : ( +
+

Add your university to join or create groups

+
+ )} + {showNewGroup && } diff --git a/src/components/molecules/Tabs/FindPeople.tsx b/src/components/molecules/Tabs/FindPeople.tsx new file mode 100644 index 00000000..00ab7151 --- /dev/null +++ b/src/components/molecules/Tabs/FindPeople.tsx @@ -0,0 +1,92 @@ +import UserListItemSkeleton from '@/components/Connections/UserListItemSkeleton' +import UserListItem from '@/components/Timeline/UserListItem' +import { useUsersProfileForConnections } from '@/services/user' +import { useUniStore } from '@/store/store' +import React, { useEffect, useRef, useState } from 'react' +import { GoSearch } from 'react-icons/go' + +export default function FindPeople() { + const [name, setName] = useState('') + const ref = useRef() + + const { userProfileData } = useUniStore() + const { + data: userProfilesData, + fetchNextPage, + isFetchingNextPage, + hasNextPage, + isLoading: isUserProfilesLoading, + } = useUsersProfileForConnections(name, 10, true) + + const userProfiles = userProfilesData?.pages.flatMap((page) => page.users) || [] + const userFollowingIDs = userProfileData && userProfileData?.following?.map((following: { userId: string }) => following.userId) + + useEffect(() => { + const handleScroll = () => { + if (ref.current) { + const { scrollTop, scrollHeight, clientHeight } = ref.current + + if (scrollTop + clientHeight >= scrollHeight - 10 && hasNextPage && !isFetchingNextPage) { + fetchNextPage() + } + } + } + + const container = ref.current + container?.addEventListener('scroll', handleScroll) + + return () => { + container?.removeEventListener('scroll', handleScroll) + } + }, [fetchNextPage, hasNextPage, isFetchingNextPage]) + + const renderUserProfileList = () => { + if (isUserProfilesLoading) { + return ( + <> + + + + + ) + } + return ( + <> + {userProfiles?.map((item, index: number) => ( + + ))} + + ) + } + + return ( + <> +
+ + setName(e.target.value)} + type="text" + value={name} + className="text-sm w-full outline-none" + placeholder="Search People" + /> +
+
+ {renderUserProfileList()} +
+ + ) +} diff --git a/src/components/molecules/Tabs/Followers.tsx b/src/components/molecules/Tabs/Followers.tsx new file mode 100644 index 00000000..0f2d8b98 --- /dev/null +++ b/src/components/molecules/Tabs/Followers.tsx @@ -0,0 +1,63 @@ +import UserListItemSkeleton from '@/components/Connections/UserListItemSkeleton' +import UserListItem from '@/components/Timeline/UserListItem' +import { useGetUserFollowers } from '@/services/connection' +import { useUniStore } from '@/store/store' +import React, { useState } from 'react' +import { GoSearch } from 'react-icons/go' + +interface Props { + userFollowingIDs: string[] +} + +export default function Followers({ userFollowingIDs }: Props) { + const [name, setName] = useState('') + const { data: userFollowers, isFetching: isFollowersLoading } = useGetUserFollowers(name, true) + + const renderUserFollowing = () => { + if (isFollowersLoading) { + return ( + <> + + + + + ) + } + return ( + <> + {userFollowers?.profile?.map((userProfile, index: number) => ( + + ))} + + ) + } + + return ( + <> +
+ + setName(e.target.value)} + type="text" + value={name} + className="text-sm w-full outline-none" + placeholder="Search People" + /> +
+
{renderUserFollowing()}
+ + ) +} diff --git a/src/components/molecules/Tabs/Following.tsx b/src/components/molecules/Tabs/Following.tsx new file mode 100644 index 00000000..86babb5b --- /dev/null +++ b/src/components/molecules/Tabs/Following.tsx @@ -0,0 +1,62 @@ +import UserListItemSkeleton from '@/components/Connections/UserListItemSkeleton' +import UserListItem from '@/components/Timeline/UserListItem' +import { useGetUserFollow } from '@/services/connection' +import React, { useState } from 'react' +import { GoSearch } from 'react-icons/go' + +interface Props { + userFollowingIDs: string[] +} + +export default function Following({ userFollowingIDs }: Props) { + const [name, setName] = useState('') + const { data: userFollowing, isFetching: isFollowingLoading } = useGetUserFollow(name, true) + + const renderUserFollowing = () => { + if (isFollowingLoading) { + return ( + <> + + + + + ) + } + return ( + <> + {userFollowing?.profile?.map((userProfile, index: number) => ( + + ))} + + ) + } + + return ( + <> +
+ + setName(e.target.value)} + type="text" + value={name} + className="text-sm w-full outline-none" + placeholder="Search People" + /> +
+
{renderUserFollowing()}
+ + ) +} diff --git a/src/components/molecules/Tabs/index.tsx b/src/components/molecules/Tabs/index.tsx index 6b3c1310..70c54128 100644 --- a/src/components/molecules/Tabs/index.tsx +++ b/src/components/molecules/Tabs/index.tsx @@ -7,9 +7,11 @@ interface TabItem { interface TabsProps { tabs: TabItem[] + className?: string + tabAlign?: 'left' | 'center' | 'right' } -const Tabs: React.FC = ({ tabs }) => { +const Tabs: React.FC = ({ tabs, className = '', tabAlign = 'left' }) => { const [activeTab, setActiveTab] = useState(0) const handleTabClick = (index: number) => { @@ -17,15 +19,15 @@ const Tabs: React.FC = ({ tabs }) => { } return ( -
+
{/* Tabs List */} -
+
{tabs.map((tab, index) => (
) } diff --git a/src/components/organism/Login/LoginBox.tsx b/src/components/organism/Login/LoginBox.tsx index bd306845..fda82c6a 100644 --- a/src/components/organism/Login/LoginBox.tsx +++ b/src/components/organism/Login/LoginBox.tsx @@ -113,7 +113,10 @@ const LoginBox = () => {
diff --git a/src/components/organism/Register/formContainer/FormContainer.tsx b/src/components/organism/Register/formContainer/FormContainer.tsx index 73a28e1b..fd24ecd8 100644 --- a/src/components/organism/Register/formContainer/FormContainer.tsx +++ b/src/components/organism/Register/formContainer/FormContainer.tsx @@ -172,7 +172,7 @@ const FormContainer = ({ step, setStep, setSubStep, subStep }: props) => { if (res?.isRegistered) { localStorage.setItem('registeredEmail', data?.email) localStorage.removeItem('registerData') - router.push('/v2/login') + router.push('/login') } return diff --git a/src/components/organisms/LeftNavbar/index.tsx b/src/components/organisms/LeftNavbar/index.tsx index 153c58e0..c1c48fe2 100644 --- a/src/components/organisms/LeftNavbar/index.tsx +++ b/src/components/organisms/LeftNavbar/index.tsx @@ -35,19 +35,20 @@ export default function LeftNavbar() { } const renderProfile = () => { - if (userProfileData.profile_dp?.imageUrl) { - return ( - profile.png - ) + console.log(userProfileData, 'userProfileData') + if (Object.keys(userProfileData).length === 0) { + return } - return + return ( + profile.png + ) } return ( diff --git a/src/components/organisms/ProfileCard/index.tsx b/src/components/organisms/ProfileCard/index.tsx new file mode 100644 index 00000000..7a2f29a2 --- /dev/null +++ b/src/components/organisms/ProfileCard/index.tsx @@ -0,0 +1,187 @@ +import Card from '@/components/atoms/Card' +import LoginButtons from '@/components/atoms/LoginButtons' +import Image from 'next/image' +import Link from 'next/link' +//import { Badge } from "@/components/ui/badge"; +//import { Button } from "@/components/ui/button"; +import { FaGraduationCap, FaEnvelope, FaPhone, FaMapMarkerAlt, FaBirthdayCake } from 'react-icons/fa' +import { ImEarth } from 'react-icons/im' +import { HiPencilAlt } from 'react-icons/hi' +import badge from '@assets/badge.svg' +import useDeviceType from '@/hooks/useDeviceType' +import { format } from 'date-fns' +import { ModalContentType } from '@/types/global' + +interface UserProfileCardProps { + name: string + isPremium: boolean + description: string + university: string + isVerified: boolean + following: number + followers: number + year: string + major: string + email: string + phone: string + location: string + birthday: string + avatarUrl: string + isVerifiedUniversity: boolean + degree: string + country: string + setModalContentType: React.Dispatch> + setIsModalOpen: React.Dispatch> +} + +export function UserProfileCard({ + name, + isPremium, + description, + university, + isVerified, + following, + followers, + year, + degree, + major, + email, + phone, + location, + birthday, + avatarUrl, + isVerifiedUniversity, + country, + setModalContentType, + setIsModalOpen, +}: UserProfileCardProps) { + const { isDesktop } = useDeviceType() + + const handleOpenModal = (modalType: ModalContentType) => { + setModalContentType(modalType) + setIsModalOpen(true) + } + return ( + +
+
+ {name} +
+
+
+
+

{name}

+ {isPremium &&

Premium

} +
+
{ + // setModalContentType('EditProfileModal') + // setIsModalOpen(true) + //}} + > + + +
+
+

{description}

+
+
+ +

{university}

+ {isVerifiedUniversity && {name}} +
+
+ handleOpenModal('ConnectionsModal')} className=" text-xs lg:text-sm cursor-pointer"> + {following || '0'} Following + + handleOpenModal('ConnectionsModal')} className=" text-xs lg:text-sm cursor-pointer"> + {following || '0'} Followers + +
+
+
+
+
+
+ + {`${degree}, ${major}`} +
+
+ + {email} +
+
+ + {phone} +
+
+ + {location} +
+
+ + {format(new Date(birthday), 'dd MMM yyyy')} +
+
+ + {country} +
+
+ {/*
+
+ {name} +
+

{name}

+ {isPremium &&

Premium

} +
+
+ Edit Profile +
+ +

{description}

+ +
+
+ University +
+ {university} + {isVerified &&

} +
+ +
+
+ {following} Following +
+
+ {followers} Followers +
+
+ +
+
+ + {`${year}, ${major}`} +
+
+ + {email} +
+
+ + {phone} +
+
+ + {location} +
+
+ + {birthday} +
+
+ + */} +
+ ) +} diff --git a/src/components/organisms/UserPostContainer/index.tsx b/src/components/organisms/UserPostContainer/index.tsx index 4bf6e707..593fa664 100644 --- a/src/components/organisms/UserPostContainer/index.tsx +++ b/src/components/organisms/UserPostContainer/index.tsx @@ -131,7 +131,7 @@ function UserPostContainer({ communityID, communityGroupID, type }: props) { style={{ boxShadow: '0px 8px 40px rgba(0, 0, 0, 0.10)' }} className="flex items-center justify-center bg-white rounded-full w-[56px] h-[56px]" > - {userProfileData?.profile_dp ? ( + {userProfileData ? ( ( endpoint: string, - { - id, - - page, - size, - data, - headers, - method, - transform = true, - customBaseUrl = false, - userCode, - email, - ...rest - }: RequestData = {} + { id, page, size, data, headers, method, transform = true, customBaseUrl = false, userCode, email, ...rest }: RequestData = {} ): Promise> => { const config: AxiosRequestConfig = { url: customBaseUrl ? `${process.env.NEXT_PUBLIC_CUSTOM_BASE_URL}/${endpoint}` : `${process.env.NEXT_PUBLIC_API_BASE_URL}/${endpoint}`, @@ -37,7 +24,6 @@ const client = async ( headers: { ...headers, 'Content-Type': 'application/json' }, params: { id, - page, size, userCode, diff --git a/src/services/auth.ts b/src/services/auth.ts index 5c82f332..31be489d 100644 --- a/src/services/auth.ts +++ b/src/services/auth.ts @@ -33,7 +33,7 @@ const register = async (data: Omit): Pr } async function register_v2(data: data) { - const response: { isRegistered: boolean } = await client(`auth/v2/register`, { method: 'POST', data }) + const response: { isRegistered: boolean } = await client(`auth/register`, { method: 'POST', data }) return response } diff --git a/src/services/connection.ts b/src/services/connection.ts index a40ac501..b1e9aad7 100644 --- a/src/services/connection.ts +++ b/src/services/connection.ts @@ -77,6 +77,7 @@ export function useGetUserFollow(Name: string, content: boolean) { queryKey: ['getUserFollow', debouncedSearchTerm], queryFn: () => getUserFollow(cookieValue, debouncedSearchTerm), enabled: !!cookieValue && content, + staleTime: 5000, }) let errorMessage = null diff --git a/src/services/universitySearch.tsx b/src/services/universitySearch.tsx index b279e24a..fb13b306 100644 --- a/src/services/universitySearch.tsx +++ b/src/services/universitySearch.tsx @@ -27,7 +27,7 @@ export async function getUniversitySearch(searchTerm: string): Promise { export function useUniversitySearchByName(universityName: string) { return useQuery({ - queryKey: ['universitySearch'], + queryKey: ['universityByName'], queryFn: () => getUniversityByName(universityName), enabled: !!universityName, // Only run if there's a search term staleTime: 0, // Optional: Cache data for 5 minutes diff --git a/src/services/user.ts b/src/services/user.ts index cdf92f31..1892f6fd 100644 --- a/src/services/user.ts +++ b/src/services/user.ts @@ -1,8 +1,10 @@ import useCookie from '@/hooks/useCookie' -import { useQuery } from '@tanstack/react-query' +import { useInfiniteQuery, useQuery } from '@tanstack/react-query' import { client } from './api-Client' import axios from 'axios' import { useUniStore } from '@/store/store' +import { ProfileConnection } from '@/types/Connections' +import useDebounce from '@/hooks/useDebounce' export async function getUserData(token: any, id: string) { const response: any = await client(`/users/${id}`, { headers: { Authorization: `Bearer ${token}` } }) @@ -25,3 +27,25 @@ export function useGetUserData(type: string) { return { ...state, error: errorMessage } } + +export async function getAllUsersForConnections(token: string, page: number, limit: number, name: string): Promise { + return await client(`/users/connections?page=${page}&limit=${limit}&name=${name}`, { headers: { Authorization: `Bearer ${token}` } }) +} + +export function useUsersProfileForConnections(name: string, limit: number, enabled: boolean) { + const [cookieValue] = useCookie('uni_user_token') + const debouncedSearchTerm = useDebounce(name, 1000) + + return useInfiniteQuery({ + queryKey: ['usersProfileForConnections', debouncedSearchTerm], + queryFn: ({ pageParam = 1 }) => getAllUsersForConnections(cookieValue, pageParam, limit, debouncedSearchTerm), + getNextPageParam: (lastPage) => { + if (lastPage.currentPage < lastPage.totalPages) { + return lastPage.currentPage + 1 + } + return undefined + }, + initialPageParam: 1, + enabled: !!cookieValue && enabled, + }) +} diff --git a/src/store/userProfileSlice/userProfileType.ts b/src/store/userProfileSlice/userProfileType.ts index 07c237b9..8a20ae5f 100644 --- a/src/store/userProfileSlice/userProfileType.ts +++ b/src/store/userProfileSlice/userProfileType.ts @@ -18,6 +18,7 @@ export interface userProfileType { country?: string city?: string university_name?: string + university_id: string study_year?: string degree?: string major?: string diff --git a/src/types/Connections/index.ts b/src/types/Connections/index.ts new file mode 100644 index 00000000..c25d401b --- /dev/null +++ b/src/types/Connections/index.ts @@ -0,0 +1,87 @@ +export interface ProfileConnection { + totalPages: number + currentPage: number + users: Users[] +} + +export interface Users { + _id: string + firstName: string + lastName: string + email: string + password: string + gender: string + dob?: string | null + role: string + isEmailVerified: boolean + createdAt: string + updatedAt: string + __v: number + joinedCommunity?: null[] | null + profile?: Profile | null + userUnVerifiedCommunities?: (UserUnVerifiedCommunitiesEntity | null)[] | null + userVerifiedCommunities?: (UserVerifiedCommunitiesEntity | null)[] | null + userName?: string | null +} +export interface Profile { + _id: string + users_id: string + dob: string + __v: number + followers?: FollowersEntity[] | null + phone_number?: string | null + totalFilled?: number | null + email?: (EmailEntity | null)[] | null + profile_dp?: ProfileDpOrCoverDp | null + affiliation?: string | null + bio?: string | null + city?: string | null + country?: string | null + degree?: string | null + major?: string | null + occupation?: string | null + study_year?: string | null + following?: FollowersEntityOrFollowingEntity[] | null + university?: string | null + cover_dp?: ProfileDpOrCoverDp1 | null +} +export interface FollowersEntity { + userId: string + _id: string + isBlock?: boolean | null +} +export interface EmailEntity { + UniversityName: string + UniversityEmail?: string | null + _id: string +} +export interface ProfileDpOrCoverDp { + imageUrl: string + publicId: string +} +export interface FollowersEntityOrFollowingEntity { + userId: string + isBlock: boolean + _id: string +} +export interface ProfileDpOrCoverDp1 { + imageUrl: string + publicId: string +} +export interface UserUnVerifiedCommunitiesEntity { + communityId: string + _id: string + communityGroups?: null[] | null +} +export interface UserVerifiedCommunitiesEntity { + communityId: string + communityName?: string | null + _id?: string | null + communityGroups?: CommunityGroupsEntity[] | null +} +export interface CommunityGroupsEntity { + communityGroupName: string + communityGroupId: string + _id: string + role?: string | null +} diff --git a/src/types/constants.ts b/src/types/constants.ts index 1f585498..bdedcd53 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -12,6 +12,7 @@ export const CommunityNavbarLinks: NavLink[] = [ ] export interface FollowingItemProps { + _id: any users_id: { firstName: string lastName: string diff --git a/tailwind.config.js b/tailwind.config.js index 4a73ef2e..801139aa 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -37,6 +37,7 @@ module.exports = { 'primary': '#6647FF', 'primary-500': '#6744FF', 'primary-700': '#3A169C', + 'primary-800': '#6400E6', 'secondary': '#F3F2FF', 'neutral-200': '#E5E7EB', 'neutral-500': '#6B7280', @@ -55,6 +56,7 @@ module.exports = { 'destructive-600': "#DC2626" }, boxShadow: { + 'logo': '0px 0px 6px 0px #00000040', 'medium': '0px 6px 15px -2px rgba(16, 24, 40, 0.08), 0px 6px 15px -2px rgba(16, 24, 40, 0.08);', 'card': '0px 6px 15px -2px rgba(16, 24, 40, 0.08)', 'button': '0px 1px 2px 0px rgba(16, 24, 40, 0.04), 0px 1px 2px 0px rgba(16, 24, 40, 0.04);', From 71a37dd27a72390b25c164cc255fa65fec3ffae2 Mon Sep 17 00:00:00 2001 From: bacpactech Date: Mon, 28 Oct 2024 12:52:06 +0530 Subject: [PATCH 2/5] fix: display name --- src/components/atoms/Card/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/atoms/Card/index.tsx b/src/components/atoms/Card/index.tsx index d625a90e..711940bd 100644 --- a/src/components/atoms/Card/index.tsx +++ b/src/components/atoms/Card/index.tsx @@ -12,4 +12,5 @@ const Card = React.forwardRef((props: TitleProps, re ) }) +Card.displayName = 'Card' export default Card From d9604895af760765821fc36855df09c3bd2c167b Mon Sep 17 00:00:00 2001 From: bacpactech Date: Thu, 7 Nov 2024 12:29:07 +0530 Subject: [PATCH 3/5] fix refactor code --- src/app/(withLayout)/connections/page.tsx | 2 +- src/app/(withLayout)/layout.tsx | 2 +- src/app/(withLayout)/profile/[...id]/page.tsx | 92 +++++++++++++++ src/app/(withLayout)/profile/page.tsx | 5 +- src/app/(withLayout)/timeline/page.tsx | 2 +- src/app/post/[id]/page.tsx | 29 +++-- .../Connections/UserListItemSkeleton.tsx | 4 +- .../Timeline/Modals/EditProfileModal.tsx | 26 +++-- src/components/Timeline/UserListItem.tsx | 16 +-- .../atoms/PostCardImagesGrid/index.tsx | 4 +- .../atoms/PostCardOption/PostCartOption.tsx | 23 +++- .../molecules/MessageNotification/index.tsx | 4 +- .../Tabs/communityGroupAll.tsx | 54 +++++++++ .../molecules/NavbarUniversityItem/index.tsx | 110 +++++++----------- .../molecules/Notification/index.tsx | 4 +- src/components/molecules/PostCard/index.tsx | 64 ++++------ src/components/molecules/Tabs/index.tsx | 2 +- src/components/organisms/LeftNavbar/index.tsx | 12 +- .../organisms/PostsContainer/index.tsx | 50 ++++++-- .../organisms/ProfileCard/index.tsx | 48 ++++---- .../organisms/UserPostContainer/index.tsx | 10 +- src/lib/utils.ts | 7 ++ src/services/community-timeline.ts | 20 ++-- src/services/community-university.ts | 11 +- src/services/user.ts | 9 +- src/types/constants.ts | 1 + src/utils/ZustandSocketProvider.tsx | 2 +- 27 files changed, 389 insertions(+), 224 deletions(-) create mode 100644 src/app/(withLayout)/profile/[...id]/page.tsx create mode 100644 src/components/molecules/NavbarUniversityItem/Tabs/communityGroupAll.tsx diff --git a/src/app/(withLayout)/connections/page.tsx b/src/app/(withLayout)/connections/page.tsx index d6dac8b9..b16dff03 100644 --- a/src/app/(withLayout)/connections/page.tsx +++ b/src/app/(withLayout)/connections/page.tsx @@ -36,7 +36,7 @@ export default function ConnectionPage() { return (
- +
) diff --git a/src/app/(withLayout)/layout.tsx b/src/app/(withLayout)/layout.tsx index 532dde96..1d13a817 100644 --- a/src/app/(withLayout)/layout.tsx +++ b/src/app/(withLayout)/layout.tsx @@ -51,7 +51,7 @@ const recommendations = [ export default function Layout({ children }: { children: React.ReactNode }) { return ( -
+
diff --git a/src/app/(withLayout)/profile/[...id]/page.tsx b/src/app/(withLayout)/profile/[...id]/page.tsx new file mode 100644 index 00000000..d5a1548d --- /dev/null +++ b/src/app/(withLayout)/profile/[...id]/page.tsx @@ -0,0 +1,92 @@ +'use client' +import Spinner from '@/components/atoms/spinner' +import PostContainer from '@/components/organisms/PostsContainer' +import { UserProfileCard } from '@/components/organisms/ProfileCard' +import Modal from '@/components/Timeline/Modal' +import ConnectionsModal from '@/components/Timeline/Modals/ConnectionsModal' +import EditProfileModal from '@/components/Timeline/Modals/EditProfileModal' +import ProfileCard from '@/components/Timeline/ProfileCard' +import { Skeleton } from '@/components/ui/Skeleton' +import { useCheckSelfProfile } from '@/lib/utils' +import { useGetUserData } from '@/services/user' +import { useUniStore } from '@/store/store' +import { PostType } from '@/types/constants' +import { ModalContentType } from '@/types/global' +import React, { useState } from 'react' + +export default function Profile({ params }: { params: { id: string } }) { + const userId = params.id[0] + const [isModalOpen, setIsModalOpen] = useState(false) + const [modalContentType, setModalContentType] = useState() + const isSelfProfile = useCheckSelfProfile(userId) + + const { data: userProfileData, isLoading: isUserProfileDataLoading } = useGetUserData(userId) + const modalContent = (modalContentType: string) => { + switch (modalContentType) { + case 'EditProfileModal': + return + case 'ConnectionsModal': + return + default: + return null + } + } + const { dob, profile, firstName, lastName, email } = userProfileData || {} + const { bio, university_name, followers, following, study_year, major, degree, phone_number, country } = profile || {} + return ( +
+ setIsModalOpen(false)}> + {modalContentType && modalContent(modalContentType)} + + {isUserProfileDataLoading || !userProfileData ? ( + + ) : ( + // + + )} + {/**/} + +
+ ) +} diff --git a/src/app/(withLayout)/profile/page.tsx b/src/app/(withLayout)/profile/page.tsx index e1d8d9ba..b2b2898b 100644 --- a/src/app/(withLayout)/profile/page.tsx +++ b/src/app/(withLayout)/profile/page.tsx @@ -1,10 +1,12 @@ 'use client' +import PostContainer from '@/components/organisms/PostsContainer' import { UserProfileCard } from '@/components/organisms/ProfileCard' import Modal from '@/components/Timeline/Modal' import ConnectionsModal from '@/components/Timeline/Modals/ConnectionsModal' import EditProfileModal from '@/components/Timeline/Modals/EditProfileModal' import ProfileCard from '@/components/Timeline/ProfileCard' import { useUniStore } from '@/store/store' +import { PostType } from '@/types/constants' import { ModalContentType } from '@/types/global' import React, { useState } from 'react' @@ -25,7 +27,7 @@ export default function Profile() { const { bio, university_name, followers, following, study_year, major, phone_number, dob, degree, country } = userProfileData const { firstName, lastName, email } = userData return ( -
+
setIsModalOpen(false)}> {modalContentType && modalContent(modalContentType)} @@ -50,6 +52,7 @@ export default function Profile() { setModalContentType={setModalContentType} setIsModalOpen={setIsModalOpen} /> +
) } diff --git a/src/app/(withLayout)/timeline/page.tsx b/src/app/(withLayout)/timeline/page.tsx index 2b28c065..b0dcdfd2 100644 --- a/src/app/(withLayout)/timeline/page.tsx +++ b/src/app/(withLayout)/timeline/page.tsx @@ -5,7 +5,7 @@ import React from 'react' export default function Timeline() { return ( -
+
diff --git a/src/app/post/[id]/page.tsx b/src/app/post/[id]/page.tsx index d06cb92f..ae08b8b1 100644 --- a/src/app/post/[id]/page.tsx +++ b/src/app/post/[id]/page.tsx @@ -2,7 +2,6 @@ import PostCard from '@/components/molecules/PostCard' import Spinner from '@/components/atoms/spinner' -import useCookie from '@/hooks/useCookie' import { useGetPost } from '@/services/community-university' import { PostType } from '@/types/constants' import { useParams, useSearchParams } from 'next/navigation' @@ -39,24 +38,24 @@ const SinglePost = () => {
) } - + const { _id, user, user_id, profile, content, createdAt, imageUrl, comments, likeCount } = item return (
-
+
{ +const UserListItemSkeleton = ({ className }: { className?: string }) => { return ( -
+
diff --git a/src/components/Timeline/Modals/EditProfileModal.tsx b/src/components/Timeline/Modals/EditProfileModal.tsx index 75f4fdac..2b482511 100644 --- a/src/components/Timeline/Modals/EditProfileModal.tsx +++ b/src/components/Timeline/Modals/EditProfileModal.tsx @@ -10,12 +10,14 @@ import { country_list } from '@/utils/countriesList' import { useForm, SubmitHandler, Controller } from 'react-hook-form' export interface editProfileInputs { - fullname: string + first_name: string + last_name: string users_id: string profile_dp?: string email?: string cover_dp?: string bio?: string + gender: string phone_number?: string dob?: string country?: string @@ -42,9 +44,11 @@ const EditProfileModal = () => { formState: { errors }, } = useForm({ defaultValues: { - fullname: userData.firstName, + first_name: userData.firstName, + last_name: userData.lastName, bio: userProfileData?.bio, phone_number: userProfileData?.phone_number, + gender: userData.gender, dob: userProfileData?.dob ? new Date(userProfileData?.dob).toISOString().split('T')[0] : '', country: userProfileData?.country, city: userProfileData?.city, @@ -74,34 +78,34 @@ const EditProfileModal = () => { First Name - {errors.fullname && Please enter first name} + {errors.first_name && Please enter first name}
- {errors.fullname && Please enter your date of birth} + {errors.last_name && Please enter your date of birth}
} + render={({ field }) => } /> - {errors.birthDate && Please enter your Birthday!} + {errors.dob && Please enter your Birthday!}