From e849eeeca58cb17102eadbb098ecf4c46b31572b Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Mon, 10 Apr 2023 22:30:42 +0100 Subject: [PATCH] Update profile page --- src/components/Navigation/navigation.ts | 2 +- src/components/Setting/UpdateProfileForm.tsx | 203 ++++++++----------- src/lib/http.ts | 2 +- src/pages/settings/profile.astro | 2 +- 4 files changed, 88 insertions(+), 121 deletions(-) diff --git a/src/components/Navigation/navigation.ts b/src/components/Navigation/navigation.ts index 356bcbb1a..9c565df63 100644 --- a/src/components/Navigation/navigation.ts +++ b/src/components/Navigation/navigation.ts @@ -2,7 +2,7 @@ import Cookies from 'js-cookie'; import { handleAuthRequired } from '../Authenticator/authenticator'; import {TOKEN_COOKIE_NAME} from "../../lib/jwt"; -function logout() { +export function logout() { Cookies.remove(TOKEN_COOKIE_NAME); // Reloading will automatically redirect the user if required window.location.reload(); diff --git a/src/components/Setting/UpdateProfileForm.tsx b/src/components/Setting/UpdateProfileForm.tsx index 4256bd145..a37ac39d2 100644 --- a/src/components/Setting/UpdateProfileForm.tsx +++ b/src/components/Setting/UpdateProfileForm.tsx @@ -1,131 +1,87 @@ -import { useCallback, useEffect, useState } from 'preact/hooks'; +import { useEffect, useState } from 'preact/hooks'; +import { httpGet, httpPost } from '../../lib/http'; import Cookies from 'js-cookie'; -import Spinner from '../Spinner'; -import {TOKEN_COOKIE_NAME} from "../../lib/jwt"; +import { TOKEN_COOKIE_NAME } from '../../lib/jwt'; -export default function UpdateProfileForm() { +export function UpdateProfileForm() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [github, setGithub] = useState(''); + const [twitter, setTwitter] = useState(''); const [linkedin, setLinkedin] = useState(''); const [website, setWebsite] = useState(''); - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); - const [message, setMessage] = useState<{ - type: 'error' | 'success' | 'info'; - message: string; - }>(); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(''); - const handleSubmit = (e: Event) => { + const handleSubmit = async (e: Event) => { e.preventDefault(); setIsLoading(true); + setError(''); + setSuccess(''); - const headers = new Headers(); - headers.append('Content-Type', 'application/json'); - headers.append( - 'Cookie', - `${TOKEN_COOKIE_NAME}=${Cookies.get(TOKEN_COOKIE_NAME)}` + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-update-profile`, + { + name, + github: github || undefined, + linkedin: linkedin || undefined, + twitter: twitter || undefined, + website: website || undefined, + } ); - fetch('http://localhost:8080/v1-update-profile', { - method: 'POST', - credentials: 'include', - headers, - body: JSON.stringify({ - name, - github: github === '' ? undefined : github, - linkedin: linkedin === '' ? undefined : linkedin, - website: website === '' ? undefined : website, - }), - }) - .then(async (res) => { - const json = await res.json(); - if (res.ok) { - return json; - } else { - throw new Error(json.message); - } - }) - .then((data) => { - setIsLoading(false); - setName(data.name); - setEmail(data.email); - if (data.links) { - const { github, linkedin, website } = data.links; - setGithub(github || ''); - setLinkedin(linkedin || ''); - setWebsite(website || ''); - } - - // Check if the user has changed their email - fetchProfile(); - setMessage({ - type: 'success', - message: 'Profile updated successfully', - }); - }) - .catch((err) => { - setIsLoading(false); - setMessage({ - type: 'error', - message: err.message || 'Something went wrong', - }); - }); + if (error || !response) { + setIsLoading(false); + setError(error?.message || 'Something went wrong'); + + return; + } + + await loadProfile(); + setSuccess('Profile updated successfully'); }; - const fetchProfile = useCallback(async () => { + const loadProfile = async () => { // Set the loading state setIsLoading(true); - // Create headers with the cookie - const headers = new Headers(); - headers.append('Content-Type', 'application/json'); - headers.append( - 'Cookie', - `${TOKEN_COOKIE_NAME}=${Cookies.get(TOKEN_COOKIE_NAME)}` + const { error, response } = await httpGet( + `${import.meta.env.PUBLIC_API_URL}/v1-me` ); - try { - const res = await fetch('http://localhost:8080/v1-me', { - method: 'POST', - credentials: 'include', - headers, - }); - - const json = await res.json(); - - if (json.status === 401) { - // If the user is not authenticated, redirect to the login page - // Clear the cookie + if (error || !response) { + if (error?.status === 401) { Cookies.remove(TOKEN_COOKIE_NAME); - window.location.href = '/login'; - } + window.location.reload(); - if (res.ok) { - setName(json.name); - setEmail(json.email); - - if (json.links) { - const { github, linkedin, website } = json.links; - setGithub(github || ''); - setLinkedin(linkedin || ''); - setWebsite(website || ''); - } - } else { - throw new Error(json.message); + return; } - } catch (error: any) { - setMessage({ - type: 'error', - message: error?.message || 'Something went wrong', - }); + + setIsLoading(false); + setError(error?.message || 'Something went wrong'); + + return; } + + const { name, email, links } = response; + + setName(name); + setEmail(email); + setGithub(links?.github || ''); + setLinkedin(links?.linkedin || ''); + setTwitter(links?.twitter || ''); + setWebsite(links?.website || ''); + setIsLoading(false); - }, []); + }; // Make a request to the backend to fill in the form with the current values useEffect(() => { - fetchProfile(); + loadProfile().finally(() => { + // hide the page level loading indicator + }); }, []); return ( @@ -144,7 +100,7 @@ export default function UpdateProfileForm() { type="text" name="name" id="name" - className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" + className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" required placeholder="John Doe" value={name} @@ -162,7 +118,7 @@ export default function UpdateProfileForm() { type="email" name="email" id="email" - className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" + className="mt-2 block w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" required disabled placeholder="john@example.com" @@ -178,12 +134,27 @@ export default function UpdateProfileForm() { type="text" name="github" id="github" - className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" + className="mt-2 block w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" placeholder="https://github.com/username" value={github} onInput={(e) => setGithub((e.target as HTMLInputElement).value)} /> +
+ + setTwitter((e.target as HTMLInputElement).value)} + /> +
+
- {message && ( -
- {message.message} -
+ {error && ( +

{error}

+ )} + + {success && ( +

+ {success} +

)} diff --git a/src/lib/http.ts b/src/lib/http.ts index 9e6c5a06b..4b68635b7 100644 --- a/src/lib/http.ts +++ b/src/lib/http.ts @@ -1,5 +1,5 @@ import Cookies from 'js-cookie'; -import {TOKEN_COOKIE_NAME} from "./jwt"; +import { TOKEN_COOKIE_NAME } from './jwt'; type AppResponse = Record; type FetchError = { diff --git a/src/pages/settings/profile.astro b/src/pages/settings/profile.astro index 29f30f89f..2f9bda4e4 100644 --- a/src/pages/settings/profile.astro +++ b/src/pages/settings/profile.astro @@ -1,6 +1,6 @@ --- import SettingSidebar from '../../components/Setting/SettingSidebar.astro'; -import UpdateProfileForm from '../../components/Setting/UpdateProfileForm'; +import { UpdateProfileForm } from '../../components/Setting/UpdateProfileForm'; import SettingLayout from '../../layouts/SettingLayout.astro'; ---