Skip to content

Commit

Permalink
Merge pull request #5 from Shubhdeep12/develop
Browse files Browse the repository at this point in the history
Feat: Added People tab, filters tab and fixed various bugs
  • Loading branch information
Shubhdeep12 committed Nov 5, 2023
2 parents 5d43210 + 8b1796c commit fdfea91
Show file tree
Hide file tree
Showing 19 changed files with 522 additions and 162 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:4000/api/v1
NEXT_PUBLIC_NODE_ENV=development
NEXT_PUBLIC_DOMAIN=.quedoor-client.com
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
.env.local

# vercel
.vercel
Expand Down
64 changes: 36 additions & 28 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ export default function Login() {
}
};

const handleLogin = async (payload: object) => {
const res = await login(payload);
if (res.status > 300) {
toast({
title: 'Failed to login! Please try again.',
variant: 'destructive',
});
} else {
toast({
title: 'User logged in successfully.',
});
updateUser(res.result);
setItem('quedoor-token', res.result.access_token);
setCookie('quedoor-token', res.result.access_token);
router.push('/');
}
};

const handleRegister = async (payload: { email: string; password: string; name: string }) => {
const res = await register(payload);
if (res.status > 300) {
toast({
title: 'Failed to register! Please try again.',
variant: 'destructive',
});
} else {
toast({
title: 'User created successfully.',
});

await handleLogin({ email: payload.email, password: payload.password });
}
};

const handleSubmit: FormEventHandler = async (e: FormEvent<HTMLInputElement>) => {
e.preventDefault();
setIsSubmitting(true);
Expand All @@ -79,19 +113,7 @@ export default function Login() {
name: username.trim(),
};
try {
const res = await register(payload);
if (res.status > 300) {
toast({
title: 'Failed to register! Please try again.',
variant: 'destructive',
});
} else {
toast({
title: 'User created successfully.',
});

setIsLoginView(true);
}
await handleRegister(payload);
} catch (error) {
toast({
title: 'Failed to register! Please try again.',
Expand All @@ -104,21 +126,7 @@ export default function Login() {
password: password,
};
try {
const res = await login(payload);
if (res.status > 300 || !res) {
toast({
title: 'Failed to login! Please try again.',
variant: 'destructive',
});
} else {
toast({
title: 'User logged in successfully.',
});
updateUser(res.result);
setItem('quedoor-token', res.result.access_token);
setCookie('quedoor-token', res.result.access_token);
router.push('/');
}
await handleLogin(payload);
} catch (error) {
toast({
title: 'Failed to login! Please try again.',
Expand Down
102 changes: 91 additions & 11 deletions app/people/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,72 @@

import { useRouter } from 'next/navigation';
import useAuth from '@/hooks/useAuth';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import PageLoader from '@/components/PageLoader';
import Text from '@/ui/Text';
import api from '@/lib/api';
import InfiniteScroll from 'react-infinite-scroll-component';
import { useInfinitePeopleList } from '@/queries/people';
import { UserProps } from '@/lib/constants';
import { Skeleton } from '@/ui/skeleton';
import NoPost from '@/assets/icons/NoPost';
import PeopleCard from '@/components/PeopleCard';
import clsx from 'clsx';

const PeopleSkeletonLoader = () => (
<div className='flex flex-col gap-6 w-full items-center'>
{Array(5)
.fill(1)
.map((e) => (
<div key={e} className='flex flex-col gap-2 w-full'>
<Skeleton className='rounded-lg h-4 w-full ' />
<Skeleton className='rounded-lg h-4 w-full' />
</div>
))}
</div>
);

const EmptyContainer = () => (
<div className='empty-container w-full h-[calc(100vh-112px)] flex flex-col justify-center items-center'>
<div className='flex flex-col items-center gap-2'>
<NoPost />
<Text className='text-sm font-semibold text-gray-500'>No User available.</Text>
</div>
</div>
);
const People = () => {
const router = useRouter();
const { user } = useAuth();
const [activeListType, setActiveListType] = useState('all');
const { data, isLoading, isFetchingNextPage, fetchNextPage, hasNextPage } = useInfinitePeopleList({
type: activeListType,
userId: user?.id,
});

const fetchUsers = async () => {
const res = await api.get('/users');
console.log({ res });
};
const peopleListTypes = [
{
id: 'all',
title: 'All',
},
{
id: 'following',
title: 'Following',
},
{
id: 'followers',
title: 'Followers',
},
];
const isEmpty = () =>
data?.pages.every((page: any) => {
return page.data && Array.isArray(page.data) && page.data.length === 0;
});

useEffect(() => {
if (!(user && user.id)) {
router.push('/login');
}
}, [user, router]);

useEffect(() => {
fetchUsers();
}, []);

if (!user) {
return <PageLoader />;
}
Expand All @@ -34,9 +76,47 @@ const People = () => {
<>
<div className='pb-4 pt-10 flex justify-between items-center bg-white w-[700px] fixed z-10'>
<Text className='text-3xl font-black'>People</Text>

<div className='flex items-center gap-4'>
{peopleListTypes.map((type) => (
<Text
key={type.id}
onClick={() => setActiveListType(type.id)}
className={clsx(
activeListType === type.id ? 'text-black' : 'text-gray-400',
'text-base font-semibold cursor-pointer transition'
)}
>
{type.title}
</Text>
))}
</div>
</div>

<div className='mt-28'>Coming soon...</div>
<div className='flex w-[700px] justify-between my-28 '>
<InfiniteScroll
next={fetchNextPage}
hasMore={hasNextPage || false}
className='!w-full'
scrollableTarget='feedscrollable'
loader={(isLoading || isFetchingNextPage) && <PeopleSkeletonLoader />}
dataLength={data?.pages.length || 0}
>
{isLoading ? (
<PeopleSkeletonLoader />
) : isEmpty() ? (
<EmptyContainer />
) : (
<div className='flex flex-col gap-6 w-full'>
{data?.pages.map((page) =>
page.data.map((user: UserProps) => (
<PeopleCard key={JSON.stringify(user)} activeListType={activeListType} user={user} />
))
)}
</div>
)}
</InfiniteScroll>
</div>
</>
);
};
Expand Down
2 changes: 1 addition & 1 deletion app/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const Profile = () => {
<Text className='text-3xl font-black'>Profile</Text>
</div>

<div className='mt-28'>Coming soon...</div>
<div className='my-28'>Coming soon...</div>
</>
);
};
Expand Down
105 changes: 103 additions & 2 deletions app/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,71 @@

import { useRouter } from 'next/navigation';
import useAuth from '@/hooks/useAuth';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import PageLoader from '@/components/PageLoader';
import Text from '@/ui/Text';
import InfiniteScroll from 'react-infinite-scroll-component';
import { useFilteredInfiniteFeed } from '@/queries/feed';
import NoPost from '@/assets/icons/NoPost';
import { Skeleton } from '@/ui/skeleton';
import { PostProps } from '@/lib/constants';
import PostCard from '@/components/PostCard';
import { Button } from '@/ui/button';
import { Dialog, DialogTrigger } from '@/ui/dialog';
import FilterPost from '@/components/FilterPost';
import clsx from 'clsx';

const EmptyContainer = () => (
<div className='empty-container w-full h-[calc(100vh-112px)] flex flex-col justify-center items-center'>
<div className='flex flex-col items-center gap-2'>
<NoPost />
<Text className='text-sm font-semibold text-gray-500'>No Post available.</Text>
<Text className='text-sm font-semibold text-gray-500'>Apply the filter or Edit the filter applied.</Text>
</div>
</div>
);

const PostSkeletonLoader = () => (
<div className='flex flex-col gap-6 w-full items-center'>
{Array(5)
.fill(1)
.map((e) => (
<div key={e} className='flex flex-col gap-4 p-8 rounded-3xl w-full max-w-[700px]'>
<div className='flex items-center gap-4 w-full'>
<Skeleton className='rounded-full h-10 w-10' />
<div className='flex flex-col gap-2 w-full'>
<Skeleton className='rounded-lg h-2 w-full ' />
<Skeleton className='rounded-lg h-2 w-full' />
</div>
</div>
<Skeleton className='rounded-lg h-3 w-full' />
<Skeleton className='rounded-lg h-3 w-full' />
<Skeleton className='h-36 w-full' />
</div>
))}
</div>
);

const Search = () => {
const router = useRouter();
const { user } = useAuth();
const [filter, setFilter] = useState<any>(null);
const [showFilterPostModal, setShowFilterPostModal] = useState(false);
const { data, isLoading, isFetchingNextPage, fetchNextPage, hasNextPage } = useFilteredInfiniteFeed(filter);
console.log(data, isLoading, isFetchingNextPage, fetchNextPage, hasNextPage);

const isFilterApplied = () => filter !== null;

const isEmpty = () =>
!data ||
data?.pages.length === 0 ||
data?.pages.every((page: any) => {
return page.data && Array.isArray(page.data) && page.data.length === 0;
});

const handleModalReset = (val: any) => {
setShowFilterPostModal(val);
};
useEffect(() => {
if (!(user && user.id)) {
router.push('/login');
Expand All @@ -24,9 +81,53 @@ const Search = () => {
<>
<div className='pb-4 pt-10 flex justify-between items-center bg-white w-[700px] fixed z-10'>
<Text className='text-3xl font-black'>Search</Text>

<Dialog open={showFilterPostModal} onOpenChange={handleModalReset}>
<DialogTrigger asChild>
<div className='flex gap-2'>
<Button
variant={'destructive'}
onClick={(e) => {
setFilter(null);
e.stopPropagation();
}}
className={clsx(isFilterApplied() ? 'w-fit' : 'w-0 p-0 m-0', 'transition-all overflow-hidden')}
>
Clear Filter
</Button>
<Button onClick={() => setShowFilterPostModal(true)}>
{isFilterApplied() ? 'Edit Filter' : 'Add Filter'}
</Button>
</div>
</DialogTrigger>
{showFilterPostModal && (
<FilterPost filter={filter} setFilter={setFilter} onClose={() => setShowFilterPostModal(false)} />
)}
</Dialog>
</div>

<div className='mt-28'>Coming soon...</div>
<div className='flex w-[700px] justify-between my-28'>
<InfiniteScroll
next={fetchNextPage}
hasMore={hasNextPage || false}
className='!w-full'
scrollableTarget='feedscrollable'
loader={(isLoading || isFetchingNextPage) && <PostSkeletonLoader />}
dataLength={data?.pages.length || 0}
>
{isLoading ? (
<PostSkeletonLoader />
) : isEmpty() ? (
<EmptyContainer />
) : (
<div className='flex flex-col gap-6 w-full'>
{data?.pages.map((page) =>
page.data.map((post: PostProps) => <PostCard key={JSON.stringify(post)} filtered post={post} />)
)}
</div>
)}
</InfiniteScroll>
</div>
</>
);
};
Expand Down
Loading

0 comments on commit fdfea91

Please sign in to comment.