feature/share-libs
tsx 153 lines 5.25 KB
Raw
1 "use client";
2
3 import { useContext, useEffect, useState } from "react";
4 import { useLogger } from "@/lib/logger";
5 import User, { usernameOrId } from "@/models/user";
6 import { useSearchParams } from "next/navigation";
7 import Image from "next/image";
8 import { invoke } from "@tauri-apps/api/tauri";
9 import { TAURI_ACCOUNT_PROFILE } from "@/lib/tauri-handler";
10 import { AccountProfileResponse } from "@/models/account";
11 import { TauriResponse } from "@/models/shared";
12 import { LocationMarkerIcon } from "@heroicons/react/solid";
13 import { GearIcon } from "@radix-ui/react-icons";
14 import Link from "next/link";
15 import { PARAMS_USER_ID } from "@/lib/params";
16 import { UserContext } from "@/lib/current-user-context";
17
18 enum State {
19 LOADING,
20 LOADED,
21 ERROR,
22 }
23
24 export default function Index() {
25 const log = useLogger("Profile/Page");
26 const searchParams = useSearchParams();
27 const userId = searchParams.get(PARAMS_USER_ID);
28 const [isOwnProfile, setIsOwnProfile] = useState(false);
29 const [userDisplayed, setUserDisplayed] = useState<User | null>(null);
30 const [state, setState] = useState(State.LOADING);
31 const userContext = useContext(UserContext);
32 const loggedInUser = userContext.user?.user;
33
34 useEffect(() => {
35 log.debug("Profile page loaded.");
36 async function fetchData() {
37 try {
38 const result = await invoke<AccountProfileResponse>(
39 TAURI_ACCOUNT_PROFILE,
40 { userId }
41 );
42 log.debug("ProfileResponse", result);
43 if (result.status === TauriResponse.ERROR) {
44 log.error("Error fetching profile");
45 return;
46 }
47 if (!result.user) {
48 log.error("No user found");
49 setState(State.ERROR);
50 return;
51 }
52
53 setIsOwnProfile(result.user.id === loggedInUser?.id);
54 setUserDisplayed(result.user);
55 setState(State.LOADED);
56 } catch (error) {
57 log.error(error);
58 setState(State.ERROR);
59 }
60 }
61 fetchData();
62 // eslint-disable-next-line react-hooks/exhaustive-deps
63 }, []);
64
65 if (state === State.LOADING) {
66 return (
67 <div className="prose prose-sm prose-invert max-w-none grid-rows-3 gap-6">
68 Loading...
69 </div>
70 );
71 }
72
73 if (state === State.ERROR) {
74 return (
75 <div className="prose prose-sm prose-invert max-w-none grid-rows-3 gap-6">
76 Error loading profile
77 </div>
78 );
79 }
80
81 if (!userDisplayed) {
82 return (
83 <div className="prose prose-sm prose-invert max-w-none grid-rows-3 gap-6">
84 User not found
85 </div>
86 );
87 }
88
89 return (
90 <div className="w-full px-4 mx-auto">
91 <div className="relative flex flex-col min-w-0 break-words mb-6 shadow-xl rounded-lg mt-16">
92 <div className="px-6">
93 <div className="flex flex-wrap justify-center">
94 <div className="w-full px-4 flex justify-center">
95 <div className="">
96 <Image
97 src={userDisplayed.gravatar_url}
98 width={150}
99 height={150}
100 className="shadow-xl rounded-full h-auto align-middle border-none absolute -m-16 -ml-20 max-w-150-px"
101 alt={userDisplayed.name}
102 />
103 </div>
104 </div>
105 <div className="w-full px-4 text-center mt-20">
106 <div className="flex justify-center py-4 lg:pt-4 pt-8">
107 <div className="mr-4 p-3 text-center">
108 <span className="text-xl font-bold block uppercase tracking-wide text-blueGray-600">
109 {userDisplayed.followers_count}
110 </span>
111 <span className="text-sm text-blueGray-400">Followers</span>
112 </div>
113 <div className="lg:mr-4 p-3 text-center">
114 <span className="text-xl font-bold block uppercase tracking-wide text-blueGray-600">
115 {userDisplayed.following_count}
116 </span>
117 <span className="text-sm text-blueGray-400">Following</span>
118 </div>
119 </div>
120 </div>
121 </div>
122 <div className="text-center mt-12">
123 <h3 className="text-xl font-semibold leading-normal text-blueGray-700 mb-2">
124 {userDisplayed.name}{" "}
125 <span className="text-blueGray-400 font-normal">
126 (@{usernameOrId(userDisplayed)})
127 </span>
128 </h3>
129 {isOwnProfile && (
130 <div className="absolute -m-4 -mr-4">
131 <Link href="/profile/update">
132 <GearIcon className="h-6 w-6 text-blueGray-300" />
133 </Link>
134 </div>
135 )}
136 <div className="text-sm leading-normal mt-0 mb-2 text-blueGray-400 font-bold uppercase">
137 <LocationMarkerIcon className="h-4 w-4 inline-block" /> Stockholm
138 </div>
139 </div>
140 <div className="mt-10 py-10 border-t border-blueGray-200 text-center">
141 <div className="flex flex-wrap justify-center">
142 <div className="w-full lg:w-9/12 px-4">
143 <p className="mb-4 text-lg leading-relaxed text-blueGray-700">
144 {userDisplayed.about}
145 </p>
146 </div>
147 </div>
148 </div>
149 </div>
150 </div>
151 </div>
152 );
153 }