Skip to content

Commit

Permalink
Merge pull request #870 from bounswe/main
Browse files Browse the repository at this point in the history
Deploying latest changes - 26.11.2023 22:09
  • Loading branch information
halisbal authored Nov 26, 2023
2 parents 03c4686 + 7079ec8 commit 6506875
Show file tree
Hide file tree
Showing 27 changed files with 845 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public Profile editProfile(String id, EditProfileRequestDto request, User user)

Profile editedProfile = profile.get();

if (request.getUsername() != null && !request.getUsername().isEmpty()) {
if (request.getUsername() != null && !request.getUsername().isEmpty() && !request.getUsername().equals(user.getUsername())) {
Optional<User> userToUpdate = userRepository.findByUsername(request.getUsername());
if (userToUpdate.isPresent()) {
throw new BadRequestException("Requested username is not available.");
Expand Down
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
Loading

0 comments on commit 6506875

Please sign in to comment.