chore: update user file assets endpoint (#438)

* chore: new service for user assets

* chore: update user file assets endpoint
This commit is contained in:
Aaryan Khandelwal
2023-03-15 11:00:42 +05:30
committed by GitHub
parent dbd6de0988
commit bfab4865cd
6 changed files with 149 additions and 78 deletions

View File

@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/router";
import useSWR from "swr";
@@ -11,15 +10,14 @@ import { useForm } from "react-hook-form";
// lib
import { requiredAuth } from "lib/auth";
// services
import projectService from "services/project.service";
import fileService from "services/file.service";
import userService from "services/user.service";
import workspaceService from "services/workspace.service";
// hooks
import useUser from "hooks/use-user";
import useToast from "hooks/use-toast";
// layouts
import AppLayout from "layouts/app-layout";
// services
import userService from "services/user.service";
import workspaceService from "services/workspace.service";
// components
import { ImageUploadModal } from "components/core";
// ui
@@ -28,18 +26,16 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import {
ChevronRightIcon,
ClipboardDocumentListIcon,
PencilIcon,
RectangleStackIcon,
UserIcon,
UserPlusIcon,
XMarkIcon,
} from "@heroicons/react/24/outline";
// types
import type { NextPage, GetServerSidePropsContext } from "next";
import type { IIssue, IUser } from "types";
import type { IUser } from "types";
// fetch-keys
import { USER_ISSUE, USER_WORKSPACE_INVITATIONS, PROJECTS_LIST } from "constants/fetch-keys";
import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys";
const defaultValues: Partial<IUser> = {
avatar: "",
@@ -50,12 +46,9 @@ const defaultValues: Partial<IUser> = {
const Profile: NextPage = () => {
const [isEditing, setIsEditing] = useState(false);
const [isRemoving, setIsRemoving] = useState(false);
const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false);
const {
query: { workspaceSlug },
} = useRouter();
const {
register,
handleSubmit,
@@ -68,65 +61,79 @@ const Profile: NextPage = () => {
const { setToastAlert } = useToast();
const { user: myProfile, mutateUser } = useUser();
const { data: myIssues } = useSWR<IIssue[]>(
myProfile && workspaceSlug ? USER_ISSUE(workspaceSlug as string) : null,
myProfile && workspaceSlug ? () => userService.userIssues(workspaceSlug as string) : null
);
const { data: invitations } = useSWR(USER_WORKSPACE_INVITATIONS, () =>
workspaceService.userWorkspaceInvitations()
);
const { data: projects } = useSWR(
workspaceSlug ? PROJECTS_LIST(workspaceSlug as string) : null,
() => (workspaceSlug ? () => projectService.getProjects(workspaceSlug as string) : null)
);
useEffect(() => {
reset({ ...defaultValues, ...myProfile });
}, [myProfile, reset]);
const onSubmit = (formData: IUser) => {
const payload: Partial<IUser> = {
id: formData.id,
first_name: formData.first_name,
last_name: formData.last_name,
avatar: formData.avatar,
};
userService
.updateUser(payload)
.then((response) => {
.then((res) => {
mutateUser((prevData) => {
if (!prevData) return prevData;
return { ...prevData, user: { ...payload, ...response } };
});
return { ...prevData, user: { ...payload, ...res } };
}, false);
setIsEditing(false);
setToastAlert({
title: "Success",
type: "success",
message: "Profile updated successfully",
title: "Success!",
message: "Profile updated successfully.",
});
})
.catch((error) => {
console.log(error);
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "There was some error in updating your profile. Please try again.",
});
});
};
const handleDelete = (url: string | null | undefined, updateUser: boolean = false) => {
if (!url) return;
setIsRemoving(true);
const index = url.indexOf(".com");
const asset = url.substring(index + 5);
fileService.deleteUserFile(asset).then(() => {
if (updateUser)
userService
.updateUser({ avatar: "" })
.then((res) => {
setIsRemoving(false);
setToastAlert({
type: "success",
title: "Success!",
message: "Profile picture removed successfully.",
});
mutateUser((prevData) => {
if (!prevData) return prevData;
return { ...prevData, user: res };
}, false);
})
.catch(() => {
setIsRemoving(false);
setToastAlert({
type: "error",
title: "Error!",
message: "There was some error in deleting your profile picture. Please try again.",
});
});
});
};
const quickLinks = [
{
icon: RectangleStackIcon,
title: "My Issues",
number: myIssues?.length ?? 0,
description: "View the list of issues assigned to you for this workspace.",
href: `/${workspaceSlug}/me/my-issues`,
},
{
icon: ClipboardDocumentListIcon,
title: "My Projects",
number: projects?.length ?? 0,
description: "View the list of projects of the workspace.",
href: `/${workspaceSlug}/projects`,
},
{
icon: UserPlusIcon,
title: "Workspace Invitations",
@@ -147,11 +154,13 @@ const Profile: NextPage = () => {
isOpen={isImageUploadModalOpen}
onClose={() => setIsImageUploadModalOpen(false)}
onSuccess={(url) => {
handleDelete(myProfile?.avatar);
setValue("avatar", url);
handleSubmit(onSubmit)();
setIsImageUploadModalOpen(false);
}}
value={watch("avatar") !== "" ? watch("avatar") : undefined}
userImage
/>
<div className="w-full space-y-5">
<Breadcrumbs>
@@ -197,15 +206,26 @@ const Profile: NextPage = () => {
<br />
Supported file types are .jpg and .png.
</p>
<Button
type="button"
className="mt-4"
onClick={() => {
setIsImageUploadModalOpen(true);
}}
>
Upload
</Button>
<div className="flex items-center gap-2">
<Button
type="button"
className="mt-4"
onClick={() => setIsImageUploadModalOpen(true)}
>
Upload new
</Button>
{myProfile.avatar && myProfile.avatar !== "" && (
<Button
type="button"
className="mt-4"
theme="danger"
onClick={() => handleDelete(myProfile.avatar, true)}
disabled={isRemoving}
>
{isRemoving ? "Removing..." : "Remove"}
</Button>
)}
</div>
</div>
</div>
<form className="space-y-5" onSubmit={handleSubmit(onSubmit)}>
@@ -259,7 +279,7 @@ const Profile: NextPage = () => {
</section>
<section>
<h2 className="mb-3 text-xl font-medium">Quick Links</h2>
<div className="grid grid-cols-3 gap-5">
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
{quickLinks.map((item, index) => (
<Link key={index} href={item.href}>
<a className="group rounded-lg bg-secondary p-5 duration-300 hover:bg-theme">