Skip to content

Commit

Permalink
Merge pull request #866 from bounswe/frontend/edit-profile
Browse files Browse the repository at this point in the history
Frontend/edit profile
  • Loading branch information
alperen-bircak authored Nov 26, 2023
2 parents 0431c5f + 9ca8fa0 commit 267b68a
Show file tree
Hide file tree
Showing 22 changed files with 642 additions and 43 deletions.
3 changes: 3 additions & 0 deletions app/frontend/public/icons/epic_games.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions app/frontend/public/icons/steam.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app/frontend/public/icons/xbox.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 3 additions & 8 deletions app/frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { RouterProvider } from "react-router-dom";
import { router } from "./router";
import "./globals.scss";
import { QueryClient, QueryClientProvider } from "react-query";
import AntdConfigProvider from "./Components/Providers/AntdConfigProvider";

const queryClient = new QueryClient();

function App() {
return (
<QueryClientProvider client={queryClient}>
<AntdConfigProvider>
<RouterProvider router={router} />
</AntdConfigProvider>
</QueryClientProvider>
<AntdConfigProvider>
<RouterProvider router={router} />
</AntdConfigProvider>
);
}

Expand Down
33 changes: 23 additions & 10 deletions app/frontend/src/Components/Forum/ForumPost/ForumPost.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,34 @@
overflow: hidden;
color: $color-text;
grid-template-rows: 30px 55px 35px;
grid-template-columns: 60px 1fr;
grid-template-columns: 60px min-content 1fr;
grid-template-areas:
"v t"
"v c"
"v m";
"v i t"
"v i c"
"v m m";

.imgConatiner {
grid-area: i;
aspect-ratio: 1;
padding: 0.5em;
img {
object-fit: contain;
height: 100%;
width: 100%;
}
}

.titleContainer {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
grid-area: t;

.title {
font-weight: bold;
font-size: 1.2em;
}
}

.content {
Expand Down Expand Up @@ -51,11 +68,7 @@
}
}
}
.title {
font-weight: bold;
font-size: 1.2em;
grid-area: t;
}

.meta {
display: flex;
align-items: end;
Expand All @@ -78,4 +91,4 @@
top: 0.5em;
right: 0.5em;
}
}
}
9 changes: 9 additions & 0 deletions app/frontend/src/Components/Forum/ForumPost/ForumPost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ function ForumPost({
/>
</div>

{post.postImage && (
<div className={styles.imgConatiner}>
<img
height="30px"
src={`${import.meta.env.VITE_APP_IMG_URL}${post.postImage}`}
/>
</div>
)}

<div className={styles.titleContainer}>
<div className={styles.title}>{post.title}</div>
{isAdmin && (
Expand Down
21 changes: 20 additions & 1 deletion app/frontend/src/Components/Hooks/useAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
useState,
} from "react";
import { me } from "../../Services/me";
import { useQuery } from "react-query";
import { getProfile } from "../../Services/profile";

type User = any;

Expand All @@ -28,6 +30,8 @@ interface UseAuthProps extends AuthContextProps {
setToken: (token: string) => void;
isLoggedIn: boolean;
logOut: () => void;
profile: any;
isLoading: boolean;
}

// Custom hook to use auth
Expand All @@ -50,7 +54,22 @@ const useAuth = (): UseAuthProps => {
location.reload();
}

return { user, setUser, token, setToken, isLoggedIn: !!user, logOut };
const { data: profile, isLoading } = useQuery(
["profile", user?.id],
() => getProfile(user?.id),
{ enabled: !!user }
);

return {
user,
setUser,
token,
setToken,
isLoggedIn: !!user,
logOut,
profile,
isLoading: !user || isLoading,
};
};

// AuthProvider component
Expand Down
125 changes: 125 additions & 0 deletions app/frontend/src/Components/Profile/EditProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { EditFilled } from "@ant-design/icons";
import { Button, Form, Input, Modal, Radio } from "antd";
import { useEffect, useState } from "react";
import { editProfile } from "../../Services/profile";
import UploadArea from "../UploadArea/UploadArea";
import { useForm } from "antd/es/form/Form";
import { useMutation, useQueryClient } from "react-query";
import { message } from "antd";

function EditProfile({ profile }: { profile: any }) {
const profileId = profile.id;
const [open, setOpen] = useState(false);
const [confirmLoading, setConfirmLoading] = useState(false);
const [imageUrl, setImageUrl] = useState<string | undefined>();
const queryClient = useQueryClient();
const [form] = useForm();

useEffect(() => {
form.setFieldsValue(profile);
form.setFieldValue("username", profile?.user?.username);
setImageUrl(profile?.profilePhoto);
}, [profile]);

const showModal = () => {
setOpen(true);
};

const { mutate: edit } = useMutation(
(data: any) => editProfile(data, profileId),
{
onSuccess() {
queryClient.invalidateQueries(["profile", profile.user.id]);
setConfirmLoading(false);
setOpen(false);
},
onError(error: any) {
message.error(error.message);
setConfirmLoading(false);
},
}
);

const handleConfirm = async (data: any) => {
setConfirmLoading(true);
const newdata = { ...data, ...{ profilePhoto: imageUrl } };
console.log(newdata);
edit(newdata);
};

const handleCancel = () => {
setOpen(false);
};

const onFinish = async (data: any) => {
await handleConfirm(data);
};

return (
<>
<Button icon={<EditFilled />} type="primary" onClick={showModal}>
Edit Profile
</Button>
<Modal
title="Edit Profile"
open={open}
onCancel={handleCancel}
style={{
maxWidth: "70%",
minWidth: "700px",
display: "flex",
flexDirection: "column",
}}
footer={[
<Button
key="submit"
type="primary"
loading={confirmLoading}
onClick={handleConfirm}
htmlType="submit"
form="editProfileForm"
>
Confirm Changes
</Button>,
]}
forceRender
>
<Form
onFinish={onFinish}
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
id="editProfileForm"
form={form}
>
<Form.Item label="Profile Photo">
<UploadArea
style={{ height: "200px", width: "200px" }}
onUpload={setImageUrl}
/>
</Form.Item>
<Form.Item label="Username" name="username">
<Input />
</Form.Item>
<Form.Item label="Privacy" name="isPrivate">
<Radio.Group>
<Radio value={true}> private </Radio>
<Radio value={false}> public </Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="Steam Profile" name="steamProfile">
<Input />
</Form.Item>
<Form.Item label="Epic Games Profile" name="epicGamesProfile">
<Input />
</Form.Item>
<Form.Item label="XBOX Profile" name="xboxProfile">
<Input />
</Form.Item>
</Form>
</Modal>
</>
);
}

export default EditProfile;
17 changes: 17 additions & 0 deletions app/frontend/src/Components/UploadArea/UploadArea.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.uploadContainer {
border: 2px dashed #d9d9d9;
border-radius: 4px;
padding: 16px;
text-align: center;

&:hover {
border-color: #40a9ff;
}
}

.dragger {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
56 changes: 56 additions & 0 deletions app/frontend/src/Components/UploadArea/UploadArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState } from "react";
import { Upload } from "antd";
import { useMutation } from "react-query";
import axios from "axios";
import styles from "./UploadArea.module.scss";
import { uploadImage } from "../../Services/image";

interface UploadAreaProps {
style?: React.CSSProperties;
onUpload?: (url: string) => void;
}

const UploadArea: React.FC<UploadAreaProps> = ({ style, onUpload }) => {
const [imageUrl, setImageUrl] = useState<string | null>(null);
const uploadMutation = useMutation(
({ image }: { image: File }) => uploadImage(image, "post-imgs"),
{
onSuccess: (data) => {
setImageUrl(data); // Assuming 'data.url' is the URL of the uploaded image
onUpload?.(data);
},
}
);

const handleUpload = async (file: any) => {
uploadMutation.mutate({ image: file });
};

return (
<div className={styles.uploadContainer} style={style}>
{!imageUrl ? (
<Upload.Dragger
name="file"
customRequest={({ file }) => handleUpload(file)}
className={styles.dragger}
showUploadList={false}
accept="image/*"
>
<p className="ant-upload-text">
Click or drag file to this area to upload
</p>
</Upload.Dragger>
) : (
<div className={styles.imagePreview}>
<img
src={`${import.meta.env.VITE_APP_IMG_URL}${imageUrl}`}
alt="Uploaded"
style={{ maxWidth: "100%", maxHeight: "100%" }}
/>
</div>
)}
</div>
);
};

export default UploadArea;
9 changes: 7 additions & 2 deletions app/frontend/src/Library/utils/handleError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import { message } from "antd";

export function handleError(error: any) {
{
const text =
(error as Error).message ?? `Unknown Error: ${JSON.stringify(error)}`;
let text;
if (typeof error === "string") {
text == error;
} else {
text =
(error as Error).message ?? `Unknown Error: ${JSON.stringify(error)}`;
}
message.error(text);
console.error(error as Error);
}
Expand Down
13 changes: 8 additions & 5 deletions app/frontend/src/Pages/Admin/Game/CreateGame/CreateGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ function CreateGame() {
},
});

const uploadImageMutation = useMutation(uploadImage, {
onError: () => {
alert("We cannot upload the image");
},
});
const uploadImageMutation = useMutation(
(i: any) => uploadImage(i, "game-icons"),
{
onError: () => {
alert("We cannot upload the image");
},
}
);
const handleClick = async () => {
const gameIcon = await uploadImageMutation.mutateAsync(
fileList[0].originFileObj
Expand Down
Loading

0 comments on commit 267b68a

Please sign in to comment.