Skip to content

Commit fec6ffe

Browse files
committed
add followers ans following option
1 parent c4515f6 commit fec6ffe

File tree

3 files changed

+272
-17
lines changed

3 files changed

+272
-17
lines changed

PRIVACYPOLICY.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Privacy Policy for Sharuco's Sharuco Website
2+
3+
Last updated: 5/1/2023
4+
5+
Thank you for visiting Sharuco's Sharuco website. Your privacy is important to us, and we are committed to protecting your personal information. This Privacy Policy describes our practices regarding the collection, use, and disclosure of your personal information.
6+
7+
## Information We Collect
8+
9+
We collect personal information that you voluntarily provide to us when you use our website. This may include your name, email address, and any other information that you provide to us when you fill out a contact form or subscribe to our newsletter.
10+
11+
We may also automatically collect certain information about your visit to our website, including your IP address, browser type and version, operating system, and website usage information.
12+
13+
## Use of Information
14+
15+
We may use your personal information to:
16+
17+
- Respond to your inquiries and provide customer support
18+
- Send you our newsletter and other marketing communications
19+
- Improve our website and user experience
20+
- Comply with legal and regulatory requirements
21+
22+
## Disclosure of Information
23+
24+
We may disclose your personal information to our third-party service providers who help us operate our website and provide customer support. We may also disclose your personal information if required by law or in the context of a legal proceeding.
25+
26+
## Cookies and Other Tracking Technologies
27+
28+
We may use cookies and other tracking technologies to collect information about your use of our website. This may include your browsing history, pages visited, and other website usage information.
29+
30+
## Links to Other Websites
31+
32+
Our website may contain links to other websites that are not operated by us. We are not responsible for the privacy practices of these third-party websites and recommend that you review their privacy policies.
33+
34+
## Your Rights
35+
36+
You may have the right to access, correct, or delete the personal information that we hold about you. If you would like to exercise your rights, please contact us at [email protected].
37+
38+
## Changes to This Privacy Policy
39+
40+
We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page. You are advised to review this Privacy Policy periodically for any changes.
41+
42+
## Contact Us
43+
44+
If you have any questions or concerns about this Privacy Policy, please contact us at [email protected].

firebase/firestore/updateAllDataOnCollection.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import {
22
collection,
33
deleteField,
44
getDocs,
5+
getDoc,
56
getFirestore,
67
updateDoc,
8+
doc,
79
} from "firebase/firestore"
810

911
import firebase_app from "../config"
@@ -37,3 +39,11 @@ export const removeAllDataOnCollection = async () => {
3739
await Promise.all(promises)
3840
console.log("La propriété a été supprimée de tous les documents")
3941
}
42+
43+
// export const addUserPseudosToLnDev7Followers = async () => {
44+
// const lnDev7Ref = doc(db, "users", "ln-dev7");
45+
// const lnDev7Data = (await getDoc(lnDev7Ref)).data();
46+
// const usersQuerySnapshot = await getDocs(collection(db, "users"));
47+
// const usersPseudos = usersQuerySnapshot.docs.map((doc) => doc.data().pseudo);
48+
// await updateDoc(lnDev7Ref, { followers: [...lnDev7Data.followers, ...usersPseudos] });
49+
// };

pages/user/[user]/index.tsx

Lines changed: 218 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,57 @@
33
import Head from "next/head"
44
import Link from "next/link"
55
import { useSearchParams } from "next/navigation"
6+
import { useAuthContext } from "@/context/AuthContext"
7+
import { useGitHubLogin } from "@/firebase/auth/githubLogin"
68
import { useDocument } from "@/firebase/firestore/getDocument"
79
import { useGetFavoriteCode } from "@/firebase/firestore/getFavoriteCode"
810
import { useGetIsPrivateCodeFromUser } from "@/firebase/firestore/getIsPrivateCodeFromUser"
9-
import { Eye, Star, Verified } from "lucide-react"
11+
import { useUpdateUserDocument } from "@/firebase/firestore/updateUserDocument"
12+
import { Eye, Github, Loader2, Star, UserIcon, Verified } from "lucide-react"
1013
import moment from "moment"
1114
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry"
1215

16+
import { cn } from "@/lib/utils"
1317
import CardCode from "@/components/card-code"
1418
import Error from "@/components/error"
1519
import { Layout } from "@/components/layout"
1620
import Loader from "@/components/loader"
1721
import LoaderCodes from "@/components/loader-codes"
22+
import {
23+
AlertDialog,
24+
AlertDialogCancel,
25+
AlertDialogContent,
26+
AlertDialogDescription,
27+
AlertDialogFooter,
28+
AlertDialogHeader,
29+
AlertDialogTitle,
30+
AlertDialogTrigger,
31+
} from "@/components/ui/alert-dialog"
1832
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
19-
import { buttonVariants } from "@/components/ui/button"
33+
import { Button, buttonVariants } from "@/components/ui/button"
34+
import {
35+
Dialog,
36+
DialogContent,
37+
DialogDescription,
38+
DialogFooter,
39+
DialogHeader,
40+
DialogTitle,
41+
DialogTrigger,
42+
} from "@/components/ui/dialog"
2043
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
2144

2245
export default function User() {
46+
const { user } = useAuthContext()
47+
const pseudo = user?.reloadUserInfo.screenName
48+
2349
const searchParams = useSearchParams()
50+
const { login, isPending } = useGitHubLogin()
51+
52+
const {
53+
data: dataUser,
54+
isLoading: isLoadingUser,
55+
isError: isErrorUser,
56+
} = useDocument(pseudo, "users")
2457

2558
const { data, isLoading, isError } = useDocument(
2659
searchParams.get("user"),
@@ -39,6 +72,28 @@ export default function User() {
3972
data: dataFavoriteCodes,
4073
} = useGetFavoriteCode(searchParams.get("user"))
4174

75+
const { updateUserDocument }: any = useUpdateUserDocument("users")
76+
77+
const addUserOnFollowers = async (pseudo: string, id: string) => {
78+
let updatedUserData = {
79+
followers: data.data.followers.includes(id)
80+
? data.data.followers.filter((item) => item !== id)
81+
: [...data.data.followers, id],
82+
}
83+
84+
updateUserDocument({ pseudo, updatedUserData })
85+
}
86+
87+
const addUserOnFollowing = async (id: string, pseudo: string) => {
88+
let updatedUserData = {
89+
following: dataUser.data.following.includes(id)
90+
? dataUser.data.following.filter((item) => item !== id)
91+
: [...dataUser.data.following, id],
92+
}
93+
94+
updateUserDocument({ pseudo, updatedUserData })
95+
}
96+
4297
return (
4398
<Layout>
4499
<Head>
@@ -73,21 +128,23 @@ export default function User() {
73128
{isLoading && <LoaderCodes isUserProfile={true} />}
74129
{data && data.exists && (
75130
<div className="flex flex-col items-center gap-4">
76-
<Avatar className="h-40 w-40 cursor-pointer">
77-
<AvatarImage
78-
src={data.data.photoURL}
79-
alt={
80-
data.data.displayName !== null
131+
<div className="relative flex items-center justify-center">
132+
<Avatar className="h-40 w-40 cursor-pointer">
133+
<AvatarImage
134+
src={data.data.photoURL}
135+
alt={
136+
data.data.displayName !== null
137+
? data.data.displayName
138+
: searchParams.get("user")
139+
}
140+
/>
141+
<AvatarFallback>
142+
{data.data.displayName !== null
81143
? data.data.displayName
82-
: searchParams.get("user")
83-
}
84-
/>
85-
<AvatarFallback>
86-
{data.data.displayName !== null
87-
? data.data.displayName
88-
: searchParams.get("user")}
89-
</AvatarFallback>
90-
</Avatar>
144+
: searchParams.get("user")}
145+
</AvatarFallback>
146+
</Avatar>
147+
</div>
91148
<div className="mb-8 flex flex-col items-center gap-2">
92149
<div className="flex items-center gap-0">
93150
<h1 className="text-center text-4xl font-bold">
@@ -107,7 +164,151 @@ export default function User() {
107164
)}
108165
</span>
109166
</div>
110-
<div className="flex flex-col items-center gap-1">
167+
{user ? (
168+
<>
169+
{user && searchParams.get("user") !== dataUser.data.pseudo ? (
170+
dataUser.data.following.includes(
171+
searchParams.get("user")
172+
) ? (
173+
<Button
174+
onClick={() => {
175+
addUserOnFollowers(
176+
searchParams.get("user"),
177+
dataUser.data.pseudo
178+
)
179+
addUserOnFollowing(
180+
searchParams.get("user"),
181+
dataUser.data.pseudo
182+
)
183+
}}
184+
className="my-2 rounded-full"
185+
>
186+
Unfollow
187+
</Button>
188+
) : (
189+
<Button
190+
onClick={() => {
191+
addUserOnFollowers(
192+
searchParams.get("user"),
193+
dataUser.data.pseudo
194+
)
195+
addUserOnFollowing(
196+
searchParams.get("user"),
197+
dataUser.data.pseudo
198+
)
199+
}}
200+
className="my-2 rounded-full"
201+
>
202+
Follow
203+
</Button>
204+
)
205+
) : null}
206+
</>
207+
) : (
208+
<AlertDialog>
209+
<AlertDialogTrigger asChild>
210+
<Button className="top-0 right-0 rounded-full">
211+
Follow
212+
</Button>
213+
</AlertDialogTrigger>
214+
<AlertDialogContent>
215+
<AlertDialogHeader>
216+
<AlertDialogTitle>
217+
Do you want to follow{" "}
218+
<a
219+
href={`/user/${searchParams.get("user")}`}
220+
className="font-semibold text-slate-900 hover:underline hover:underline-offset-4 dark:text-slate-100"
221+
>
222+
{searchParams.get("user")}
223+
</a>{" "}
224+
?
225+
</AlertDialogTitle>
226+
<AlertDialogDescription>
227+
Join Sharuco now !
228+
</AlertDialogDescription>
229+
</AlertDialogHeader>
230+
<AlertDialogFooter>
231+
<AlertDialogCancel>Cancel</AlertDialogCancel>
232+
<button
233+
className={cn(
234+
"inline-flex h-10 items-center justify-center rounded-md bg-slate-900 py-2 px-4 text-sm font-semibold text-white transition-colors hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900"
235+
)}
236+
disabled={isPending}
237+
onClick={login}
238+
>
239+
{isPending ? (
240+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
241+
) : (
242+
<Github className="mr-2 h-4 w-4" />
243+
)}
244+
Login with Github
245+
</button>
246+
</AlertDialogFooter>
247+
</AlertDialogContent>
248+
</AlertDialog>
249+
)}
250+
<div className="flex flex-col items-center gap-2">
251+
<div className="flex items-center gap-2 text-md font-semibold text-slate-900 dark:text-slate-100">
252+
<Dialog>
253+
<DialogTrigger asChild>
254+
<span className="cursor-pointer hover:underline hover:underline-offset-2">
255+
{data.data.followers.length} followers
256+
</span>
257+
</DialogTrigger>
258+
<DialogContent className="max-h-[640px] overflow-hidden overflow-y-auto scrollbar-hide">
259+
<DialogHeader>
260+
<DialogTitle>Followers</DialogTitle>
261+
</DialogHeader>
262+
<div className="flex flex-wrap gap-2">
263+
{data.data.followers.map((follower) => (
264+
<a
265+
href={`/user/${follower}`}
266+
key={follower}
267+
className="w-full bg-slate-100 border-2 border-transparent dark:bg-slate-700 px-4 py-2 rounded-lg flex items-center justify-start gap-2 text-sm font-semibold text-slate-900 dark:text-slate-100 hover:border-2 hover:border-sky-400"
268+
>
269+
<UserIcon className="h-4 w-4" />
270+
<span className="hover:underline">{follower}</span>
271+
</a>
272+
))}
273+
{data.data.followers.length === 0 && (
274+
<p className="text-sm font-semibold text-slate-900 dark:text-slate-100">
275+
This user has no followers yet.
276+
</p>
277+
)}
278+
</div>
279+
</DialogContent>
280+
</Dialog>
281+
<span></span>
282+
<Dialog>
283+
<DialogTrigger asChild>
284+
<span className="cursor-pointer hover:underline hover:underline-offset-2">
285+
{data.data.following.length} following
286+
</span>
287+
</DialogTrigger>
288+
<DialogContent className="max-h-[640px] overflow-hidden overflow-y-auto scrollbar-hide">
289+
<DialogHeader>
290+
<DialogTitle>Following</DialogTitle>
291+
</DialogHeader>
292+
<div className="flex flex-wrap gap-2">
293+
{data.data.following.map((following) => (
294+
<a
295+
href={`/user/${following}`}
296+
key={following}
297+
className="w-full bg-slate-100 border-2 border-transparent dark:bg-slate-700 px-4 py-2 rounded-lg flex items-center justify-start gap-2 text-sm font-semibold text-slate-900 dark:text-slate-100 hover:border-2 hover:border-sky-400"
298+
>
299+
<UserIcon className="h-4 w-4" />
300+
<span className="hover:underline">{following}</span>
301+
</a>
302+
))}
303+
{data.data.following.length === 0 && (
304+
<p className="text-sm font-semibold text-slate-900 dark:text-slate-100">
305+
This user has no following yet.
306+
</p>
307+
)}
308+
</div>
309+
</DialogContent>
310+
</Dialog>
311+
</div>
111312
<p className="text-center text-gray-500">
112313
Joined{" "}
113314
<span className="font-bold">

0 commit comments

Comments
 (0)