Skip to content

Commit

Permalink
Merge pull request #90 from jpcmf/develop
Browse files Browse the repository at this point in the history
Develop to Main
  • Loading branch information
jpcmf authored Dec 7, 2024
2 parents f03bc19 + 83fb496 commit a3c7b60
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 31 deletions.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,31 @@ And that's it! Your `SkateHub Frontend` should now be up and running locally on

### 2024

- 2024-12-07 - Implement user profile update functionality in AuthContext [#89](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/89) _(v0.1.27)_
- 2024-12-07 - Create `textarea` form component [#88](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/88) _(v0.1.26)_
- 2024-11-19 - Add reCAPTCHA verification to sign-up process [#70](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/70) _(v0.1.25)_
- 2024-11-19 - Add Lint-Staged to enhance pre-commit validations [#65](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/65) _(v0.1.24)_
- 2024-11-19 - Create an API Route for the Sitemap [#62](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/62) _(v0.1.23)_
- 2024-11-13 - Add reCAPTCHA verification to sign-in process [#59](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/59) _(v0.1.22)_
- 2024-11-08 - Add Husky [#53](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/53) _(v0.1.21)_
- 2024-11-08 - Add vercel development deployment configuration [#31](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/31) _(v0.1.20)_
- 2024-11-06 - Add the `forgot-password` button [#25](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/25) _(v0.1.19)_
- 2024-11-06 - Add `forgot-password` button [#25](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/25) _(v0.1.19)_
- 2024-11-06 - Upgrade libraries [#23](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/23) _(v0.1.18)_
- 2024-11-06 - Create the `reset password` page [#21](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/21) _(v0.1.17)_
- 2024-04-28 - Update the `forgot-password` page of the SkateHub project [#20](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/20) _(v0.1.16)_
- 2024-11-06 - Create `reset password` page [#21](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/21) _(v0.1.17)_
- 2024-04-28 - Update `forgot-password` page [#20](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/20) _(v0.1.16)_
- 2024-04-28 - Redirect to the root route when attempting to access /auth [#19](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/19) _(v0.1.15)_
- 2024-04-28 - Create the `forgot-password` page of the SkateHub project [#18](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/18) _(v0.1.14)_
- 2024-04-11 - Update the `signin` page of the SkateHub project [#17](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/17) _(v0.1.13)_
- 2024-04-08 - Create the `confirmation` page of the SkateHub project [#15](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/15) _(v0.1.12)_
- 2024-04-06 - Update the `signin` page of the SkateHub project [#14](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/14) _(v0.1.11)_
- 2024-04-03 - Create the `signup` page of the SkateHub project [#12](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/12) _(v0.1.10)_
- 2024-04-28 - Create `forgot-password` page [#18](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/18) _(v0.1.14)_
- 2024-04-11 - Update `signin` page [#17](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/17) _(v0.1.13)_
- 2024-04-08 - Create `confirmation` page [#15](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/15) _(v0.1.12)_
- 2024-04-06 - Update `signin` page [#14](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/14) _(v0.1.11)_
- 2024-04-03 - Create `signup` page [#12](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/12) _(v0.1.10)_
- 2024-03-31 - Update `authentication` and `session` management [#11](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/11) _(v0.1.9)_
- 2024-03-29 - Create the `toast` component [#10](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/10) _(v0.1.8)_
- 2024-03-27 - Add the `favicon` of the SkateHub project [#9](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/9) _(v0.1.7)_
- 2024-03-27 - Add the `favicon` [#9](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/9) _(v0.1.7)_
- 2024-03-27 - Add the `prettier.config.js` file to the project to handle with code formatter [#8](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/8) _(v0.1.6)_
- 2024-03-27 - Create the `signin` page of the SkateHub project [#7](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/7) _(v0.1.5)_
- 2024-03-27 - Create the `signin` page [#7](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/7) _(v0.1.5)_
- 2024-03-26 - Create the `header` component [#5](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/5) _(v0.1.4)_
- 2024-03-26 - Create the `home` page of the SkateHub project [#4](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/4) _(v0.1.3)_
- 2024-03-26 - Create the `home` page [#4](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/4) _(v0.1.3)_
- 2024-03-26 - Create the `sidebar` provider and components to handle with the aside menu [#3](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/3) _(v0.1.2)_
- 2024-03-24 - Add [Chakra UI](https://chakra-ui.com/) to handle with the user interface [#2](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/2) _(v0.1.1)_
- 2024-03-19 - Add a quick guide to getting started with the application [#1](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/1) _(v0.1.0)_
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "0.1.25",
"name": "skatehub-frontend",
"version": "0.1.27",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
16 changes: 10 additions & 6 deletions src/components/Header/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useRouter } from "next/router";
import { useContext } from "react";
import { RiLogoutCircleLine } from "react-icons/ri";
import {
Expand All @@ -20,6 +21,7 @@ interface ProfileProps {
}

export function Profile({ showProfileData = true }: ProfileProps) {
const router = useRouter();
const { user, signOut } = useContext(AuthContext);

return (
Expand All @@ -39,14 +41,16 @@ export function Profile({ showProfileData = true }: ProfileProps) {

<MenuList bg="gray.900" borderColor="gray.800">
<MenuGroup title="Minha conta">
<MenuItem color="gray.600" bg="gray.900" _hover={{ color: "white" }}>
{user?.about}
</MenuItem>
<MenuItem color="gray.600" bg="gray.900" _hover={{ color: "white" }}>
My Account
<MenuItem
color="gray.600"
bg="gray.900"
_hover={{ color: "white" }}
onClick={() => router.push("/user/edit")}
>
Editar
</MenuItem>
<MenuItem color="gray.600" bg="gray.900" _hover={{ color: "white" }}>
Payments{" "}
{user?.about}
</MenuItem>
<MenuDivider />
<MenuItem
Expand Down
73 changes: 62 additions & 11 deletions src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Router from "next/router";
import { createContext, useEffect, useState } from "react";
import { destroyCookie, parseCookies, setCookie } from "nookies";

import { signInRequest, userMe } from "../services/auth";
import { signInRequest, updateUserProfile, userMe } from "../services/auth";

type SignInData = {
email: string;
Expand All @@ -11,37 +11,70 @@ type SignInData = {
};

type User = {
id: string;
name: string;
email: string;
about: string;
username: string;
avatar_url: string;
website_url: string;
};

type UpdateUserData = Pick<User, "id" | "name" | "email" | "about" | "website_url">;

type AuthContextType = {
isAuthenticated: boolean;
user: User | null;
signIn: (data: SignInData) => Promise<void>;
signOut: () => void;
updateUser: (data: UpdateUserData) => Promise<void>;
token: string | null;
isLoading: boolean;
};

export const AuthContext = createContext({} as AuthContextType);

export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);

const isAuthenticated = !!user;

useEffect(() => {
const { "nextauth.token": token } = parseCookies();

if (token) {
userMe(token)
.then(response => {
setUser(response);
})
.catch(() => {
async function loadUserData() {
if (token) {
try {
setToken(token);
userMe(token)
.then(response => {
const userData = response.user || response;
setUser({
id: userData.id,
name: userData.name || userData.username || "User",
email: userData.email,
about: userData.about || "",
username: userData.username,
avatar_url: userData.avatar_url || "",
website_url: userData.website_url || ""
});
})
.catch(() => {
signOut();
});
} catch (error) {
signOut();
});
} finally {
setIsLoading(false);
}
} else {
setIsLoading(false);
}
}

loadUserData();
}, []);

async function signIn({ email, password }: SignInData) {
Expand All @@ -53,16 +86,34 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
});

setUser(user);
console.table(user);

setToken(jwt);
Router.push("/dashboard");
}

async function updateUser(data: UpdateUserData) {
if (!user || !token) {
throw new Error("No authenticated user.");
}

try {
const updatedUser = await updateUserProfile(token, data);
setUser(prevUser => (prevUser ? { ...prevUser, ...updatedUser } : null));
} catch (error) {
console.error("Failed to update user.", error);
throw error;
}
}

function signOut() {
setUser(null);
setToken("");
destroyCookie(undefined, "nextauth.token");
Router.push("/auth/signin");
}

return <AuthContext.Provider value={{ user, isAuthenticated, signIn, signOut }}>{children}</AuthContext.Provider>;
return (
<AuthContext.Provider value={{ user, isAuthenticated, signIn, signOut, token, isLoading, updateUser }}>
{children}
</AuthContext.Provider>
);
}
131 changes: 131 additions & 0 deletions src/features/user/edit/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { useRouter } from "next/router";
import { useContext, useEffect } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { Box, Button, Flex, Heading, Divider, SimpleGrid, VStack, HStack } from "@chakra-ui/react";

import { Input } from "@/shared/components/Form/Input";
import { Toast } from "@/components/Toast";
import { Layout } from "@/shared/components/Layout";
import { Textarea } from "@/shared/components/Form/Textarea";
import { AuthContext } from "@/contexts/AuthContext";

type RegisterForm = {
name: string;
email: string;
about: string;
website_url: string;
// password: string;
// password_confirmation: string;
};

export function UserEdit() {
const router = useRouter();
const { addToast } = Toast();

const { user, updateUser } = useContext(AuthContext);

const {
register,
handleSubmit,
formState: { errors, isSubmitting },
reset
} = useForm<RegisterForm>();

useEffect(() => {
if (user) {
reset(user);
}
}, [user, reset]);

const handleEditUser: SubmitHandler<RegisterForm> = async values => {
try {
await updateUser({
id: user ? user.id : "",
name: values.name,
email: values.email,
about: values.about,
website_url: values.website_url
});

addToast({
title: "Usuário editado com sucesso.",
message: "Seu perfil foi atualizado.",
type: "success"
});
} catch (error) {
addToast({
title: "Erro ao editar usuário.",
message: `Ocorreu um erro ao editar seu perfil: ${error}`,
type: "error"
});
console.log("Erro ao editar usuário:", error);
}
};

return (
<Layout>
<Box as="form" onSubmit={handleSubmit(handleEditUser)} flex="1" borderRadius={8} bg="gray.800" p={["6", "8"]}>
<Flex mb="8" direction="column">
<Heading size="lg" fontWeight="normal">
Editar
</Heading>
<Divider my="6" borderColor="gray.700" />
<VStack spacing="4">
<SimpleGrid minChildWidth="240px" spacing="4" w="100%">
<Input label="Nome completo" {...register("name")} error={errors.name} isDisabled />
<Input type="email" label="E-mail" {...register("email")} error={errors.email} />
</SimpleGrid>
<SimpleGrid minChildWidth="240px" spacing="4" w="100%">
<Flex flexDirection="column">
<Textarea label="Sobre você" placeholder="Sobre você..." {...register("about")} error={errors.about} />
</Flex>
</SimpleGrid>
<SimpleGrid minChildWidth="240px" spacing="4" w="100%">
<Input
isInputGroup
InputLeftAddonText="instagram.com/"
label="Perfil Instagram"
placeholder="Ex. nome_do_usuário"
/>
<Input
isInputGroup
InputLeftAddonText="https://"
label="Website Pessoal"
placeholder="Ex. www.site.com.br"
{...register("website_url")}
error={errors.website_url}
/>
</SimpleGrid>

{/* <SimpleGrid minChildWidth="240px" spacing={["6", "8"]} w="100%">
<Input type="password" label="Senha" {...register("password")} error={errors.password} />
<Input
type="password"
label="Confirmar senha"
{...register("password_confirmation")}
error={errors.password_confirmation}
/>
</SimpleGrid> */}
</VStack>
<Flex mt="8" justify="flex-end">
<HStack spacing="4">
<Button as="a" size="lg" fontSize="sm" colorScheme="whiteAlpha" onClick={() => router.push("/dashboard")}>
Cancelar
</Button>
<Button
type="submit"
isLoading={isSubmitting}
size="lg"
fontSize="sm"
colorScheme="green"
isDisabled={!user?.email}
>
Salvar
</Button>
</HStack>
</Flex>
</Flex>
</Box>
</Layout>
);
}
5 changes: 5 additions & 0 deletions src/pages/user/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { UserEdit } from "@/features/user/edit";

export default function UserEditPage() {
return <UserEdit />;
}
Loading

0 comments on commit a3c7b60

Please sign in to comment.