Skip to content

Commit 815d699

Browse files
top users
1 parent 5936e20 commit 815d699

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

src/components/users/Users.tsx

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { useCallback, useContext, useEffect, useState } from 'react'
2+
import {
3+
Accordion,
4+
AccordionContent,
5+
AccordionItem,
6+
AccordionTrigger,
7+
} from '@/components/ui/accordion'
8+
import {
9+
Card,
10+
CardContent,
11+
CardDescription,
12+
CardFooter,
13+
CardHeader,
14+
CardTitle,
15+
} from '@/components/ui/card'
16+
import fetchUsers from '@/api/fetchUsers'
17+
import { ContextTopUsers } from '@/context/ContextTopUsers'
18+
import { UsersType } from '@/types/types'
19+
import { getItemFromSessionStorage } from '@/utils/getItemFromSessionStorage'
20+
import { useScreenWidth } from '@/hooks/useScreenWidth'
21+
22+
const Users = () => {
23+
const contextTopUsersRef = useContext(ContextTopUsers)
24+
if (!contextTopUsersRef) {
25+
throw new Error(
26+
'Users must be used within a contextTopUsersRef.Provider'
27+
)
28+
}
29+
const topUsersRef = contextTopUsersRef
30+
31+
const [users, setUsers] = useState<Array<UsersType>>([])
32+
const [isLoading, setIsLoading] = useState(false)
33+
34+
const SCREEN_WIDTH = useScreenWidth()
35+
36+
const loadUsers = useCallback(async () => {
37+
if (isLoading) {
38+
return
39+
}
40+
setIsLoading(true)
41+
await fetchUsers(setUsers)
42+
setIsLoading(false)
43+
}, [isLoading])
44+
45+
useEffect(() => {
46+
const parsedStorageData = getItemFromSessionStorage()
47+
setUsers(parsedStorageData?.users || [])
48+
49+
if (!parsedStorageData?.users?.length) {
50+
loadUsers()
51+
}
52+
}, [loadUsers])
53+
54+
return (
55+
<section
56+
className="w-full flex flex-col items-center gap-8 lg:gap-12 max-w-7xl p-6 lg:py-8 min-[1304px]:px-0"
57+
ref={topUsersRef}
58+
>
59+
<div className="w-full flex flex-col items-center">
60+
<div className="w-full flex flex-col gap-4">
61+
<h2 className="text-very-large font-semibold text-zinc-50 underline">
62+
Most Active Users
63+
</h2>
64+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 w-full">
65+
{SCREEN_WIDTH !== 'MOBILE' && (
66+
<div className="md:col-span-2 grid grid-cols-1 sm:grid-cols-2 gap-4">
67+
{users.length > 0
68+
? users.slice(0, 4).map((item) => (
69+
<Card key={item.id} className="gap-4">
70+
<CardHeader>
71+
<CardTitle>
72+
{item.name}
73+
</CardTitle>
74+
<CardDescription>
75+
{item.email}
76+
</CardDescription>
77+
</CardHeader>
78+
<CardContent>
79+
<p>{item.company.name}</p>
80+
<p>{item.company.bs}</p>
81+
</CardContent>
82+
<CardFooter>
83+
{item.website}
84+
</CardFooter>
85+
</Card>
86+
))
87+
: null}
88+
</div>
89+
)}
90+
<div className="flex flex-col gap-4">
91+
{users.length > 4 ? (
92+
<Card className="h-full">
93+
<CardHeader className="hidden sm:flex">
94+
<CardTitle className="underline pb-2">
95+
More Active Users
96+
</CardTitle>
97+
</CardHeader>
98+
<CardContent>
99+
<Accordion
100+
type="single"
101+
collapsible
102+
defaultValue={`item-${
103+
SCREEN_WIDTH === 'MOBILE'
104+
? '1'
105+
: '5'
106+
}`}
107+
>
108+
{users
109+
.slice(
110+
SCREEN_WIDTH === 'MOBILE'
111+
? 0
112+
: 4
113+
)
114+
.map((item) => (
115+
<AccordionItem
116+
value={`item-${item.id.toString()}`}
117+
key={item.id}
118+
>
119+
<AccordionTrigger>
120+
<CardTitle>
121+
{item.name}
122+
</CardTitle>
123+
</AccordionTrigger>
124+
<AccordionContent>
125+
<CardDescription>
126+
<p>
127+
{item.email}
128+
</p>
129+
</CardDescription>
130+
<CardFooter className="px-0">
131+
<p>
132+
{
133+
item.website
134+
}
135+
</p>
136+
</CardFooter>
137+
</AccordionContent>
138+
</AccordionItem>
139+
))}
140+
</Accordion>
141+
</CardContent>
142+
</Card>
143+
) : null}
144+
</div>
145+
</div>
146+
</div>
147+
</div>
148+
</section>
149+
)
150+
}
151+
152+
export default Users

0 commit comments

Comments
 (0)