forked from Transparency/kgroad-frontend2
added change-image feature in profile, sign-up validating password and shows correct error, if user already exists
This commit is contained in:
1 parent
6650a98503
commit
0a7513dd89
5 files changed
+398
-27
No files matched your search
@@ -3,9 +3,14 @@
|
||||
import Image from "next/image";
|
||||
import "./ProfileAvatar.scss";
|
||||
import pen from "./icons/pen.svg";
|
||||
import close from "./icons/close.svg";
|
||||
import close_white from "./icons/close-white.svg";
|
||||
import { authInstanse } from "@/shared/config/apiConfig";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useState } from "react";
|
||||
import { AxiosError } from "axios";
|
||||
import Loader from "@/shared/ui/components/Loader/Loader";
|
||||
|
||||
interface IProfileAvatarProps {
|
||||
img: string;
|
||||
@@ -14,29 +19,109 @@ interface IProfileAvatarProps {
|
||||
const ProfileAvatar: React.FC<IProfileAvatarProps> = ({
|
||||
img,
|
||||
}: IProfileAvatarProps) => {
|
||||
const [modal, setModal] = useState<boolean>(false);
|
||||
const [display_image, setDisplayImage] = useState<File | string>(
|
||||
img
|
||||
);
|
||||
const [isDeleting, setIsDeleting] = useState<boolean>(false);
|
||||
const [message, setMessage] = useState<boolean>(false);
|
||||
const def =
|
||||
"https://api.kgroaduat.fishrungames.com/media/user_photo/default.webp";
|
||||
|
||||
const [success, setSuccess] = useState<string>("");
|
||||
const [loader, setLoader] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
const session = useSession();
|
||||
const router = useRouter();
|
||||
const changeImage: React.ChangeEventHandler<
|
||||
HTMLInputElement
|
||||
> = async (e) => {
|
||||
const formData = new FormData();
|
||||
|
||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (
|
||||
e
|
||||
) => {
|
||||
if (e.target.files) {
|
||||
const image = Array.from(e.target.files);
|
||||
formData.append("image", image[0]);
|
||||
}
|
||||
|
||||
if (session.status === "unauthenticated") return;
|
||||
|
||||
try {
|
||||
const res = await authInstanse(
|
||||
session.data?.access_token as string
|
||||
).patch("/users/update_image/", formData);
|
||||
router.refresh();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setDisplayImage(e.target.files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const changeImage = async () => {
|
||||
const formData = new FormData();
|
||||
|
||||
if (session.status === "unauthenticated") return;
|
||||
|
||||
if (
|
||||
typeof display_image === typeof "string" ||
|
||||
display_image === img
|
||||
)
|
||||
return;
|
||||
|
||||
formData.append("image", display_image);
|
||||
|
||||
try {
|
||||
setLoader(true);
|
||||
const res = await authInstanse(
|
||||
session.data?.access_token as string
|
||||
).patch("/users/update_image/", formData);
|
||||
|
||||
setError("");
|
||||
setSuccess("Фото профиля обновлено");
|
||||
setMessage(true);
|
||||
router.refresh();
|
||||
|
||||
setTimeout(() => {
|
||||
setMessage(false);
|
||||
}, 3000);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
setSuccess("");
|
||||
setError(error.message);
|
||||
setMessage(true);
|
||||
setTimeout(() => {
|
||||
setMessage(false);
|
||||
}, 3000);
|
||||
}
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
const returnDefaultImage = async () => {
|
||||
if (session.status === "unauthenticated") return;
|
||||
|
||||
try {
|
||||
setLoader(true);
|
||||
const res = await authInstanse(
|
||||
session.data?.access_token as string
|
||||
).patch("/users/delete_image/", {});
|
||||
|
||||
setError("");
|
||||
setSuccess("Фото профиля удалено");
|
||||
setMessage(true);
|
||||
setDisplayImage(def);
|
||||
router.refresh();
|
||||
|
||||
setTimeout(() => {
|
||||
setMessage(false);
|
||||
}, 3000);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
setSuccess("");
|
||||
setError(error.message);
|
||||
setMessage(true);
|
||||
setTimeout(() => {
|
||||
setMessage(false);
|
||||
}, 3000);
|
||||
}
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
const imageIsString =
|
||||
typeof display_image === "string"
|
||||
? display_image
|
||||
: typeof display_image === "undefined"
|
||||
? ""
|
||||
: URL.createObjectURL(display_image as File);
|
||||
return (
|
||||
<div className="profile-avatar">
|
||||
<img
|
||||
@@ -44,10 +129,123 @@ const ProfileAvatar: React.FC<IProfileAvatarProps> = ({
|
||||
src={img}
|
||||
alt="User Image"
|
||||
/>
|
||||
<label htmlFor="profile-image">
|
||||
<button
|
||||
onClick={() => setModal(true)}
|
||||
className="profile-avatar__change-btn"
|
||||
>
|
||||
<Image src={pen} alt="Pen Icon" />
|
||||
</label>
|
||||
<input onChange={changeImage} id="profile-image" type="file" />
|
||||
</button>
|
||||
|
||||
{modal && (
|
||||
<div
|
||||
onClick={() => setModal(false)}
|
||||
className="profile-avatar__modal"
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="profile-avatar__wrapper"
|
||||
>
|
||||
<div className="profile-avatar__text">
|
||||
<div>
|
||||
<h4>Фото профиля</h4>
|
||||
<button onClick={() => setModal(false)}>
|
||||
<Image src={close} alt="Close Icon" />
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
По фото профиля другие люди смогут вас узнавать, а вам
|
||||
будет проще определять, в какой аккаунт вы вошли.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<img
|
||||
className="profile-avatar__user-img"
|
||||
src={imageIsString}
|
||||
alt="User image"
|
||||
/>
|
||||
<div className="profile-avatar__btns">
|
||||
{img === def && display_image === def ? (
|
||||
<>
|
||||
<label
|
||||
className="profile-avatar__blue-btn"
|
||||
htmlFor="change-image"
|
||||
>
|
||||
Добавить фото профиля
|
||||
</label>
|
||||
<input
|
||||
onChange={handleChange}
|
||||
id="change-image"
|
||||
type="file"
|
||||
/>
|
||||
</>
|
||||
) : isDeleting ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsDeleting(false)}
|
||||
className="profile-avatar__gray-btn"
|
||||
>
|
||||
Отмена
|
||||
</button>
|
||||
<button
|
||||
onClick={returnDefaultImage}
|
||||
disabled={loader}
|
||||
className="profile-avatar__blue-btn"
|
||||
>
|
||||
{loader ? <Loader /> : "Удалить"}
|
||||
</button>
|
||||
</>
|
||||
) : img === display_image || success !== "" ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsDeleting(true)}
|
||||
className="profile-avatar__gray-btn"
|
||||
>
|
||||
Удалить
|
||||
</button>
|
||||
<label
|
||||
className="profile-avatar__blue-btn"
|
||||
htmlFor="change-image"
|
||||
>
|
||||
Сменить
|
||||
</label>
|
||||
<input
|
||||
onChange={handleChange}
|
||||
id="change-image"
|
||||
type="file"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setDisplayImage(img)}
|
||||
className="profile-avatar__gray-btn"
|
||||
>
|
||||
Назад
|
||||
</button>
|
||||
<button
|
||||
disabled={loader}
|
||||
onClick={changeImage}
|
||||
className="profile-avatar__blue-btn"
|
||||
>
|
||||
{loader ? <Loader /> : "Сохранить"}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{message && (
|
||||
<div className="profile-avatar__message">
|
||||
<p>
|
||||
{success} {error}
|
||||
</p>
|
||||
<button onClick={() => setMessage(false)}>
|
||||
<Image src={close_white} alt="Close Icon White" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user