From 98f3412db0ce66be1c358d4c59728d40379d6ddc Mon Sep 17 00:00:00 2001 From: abhishake1 Date: Mon, 6 Nov 2023 13:50:49 +0000 Subject: [PATCH 1/5] fix: newly added cycle doesnt appear unlelss the page is manually reloaded --- "\\" | 391 ++++++++++++++++++ web/components/cycles/cycles-view.tsx | 2 +- .../profile-layout/profile-sidebar.tsx | 34 ++ .../projects/[projectId]/cycles/index.tsx | 5 +- web/store/cycle/cycles.store.ts | 1 + 5 files changed, 430 insertions(+), 3 deletions(-) create mode 100644 "\\" create mode 100644 web/layouts/profile-layout/profile-sidebar.tsx diff --git "a/\\" "b/\\" new file mode 100644 index 00000000000..d50b2108a50 --- /dev/null +++ "b/\\" @@ -0,0 +1,391 @@ +import React, { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import Link from "next/link"; + +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// services +import fileService from "services/file.service"; +import userService from "services/user.service"; +// hooks +import useUserAuth from "hooks/use-user-auth"; +import useToast from "hooks/use-toast"; +// layouts +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; +// components +import { ImagePickerPopover, ImageUploadModal } from "components/core"; +import { SettingsSidebar } from "components/project"; +// ui +import { CustomSearchSelect, CustomSelect, Input, PrimaryButton, Spinner } from "components/ui"; +import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// icons +import { UserIcon } from "@heroicons/react/24/outline"; +import { UserCircle } from "lucide-react"; +// types +import type { NextPage } from "next"; +import type { IUser } from "types"; +// constants +import { USER_ROLES } from "constants/workspace"; +import { TIME_ZONES } from "constants/timezones"; + +const defaultValues: Partial = { + avatar: "", + cover_image: "", + first_name: "", + last_name: "", + email: "", + role: "Product / Project Manager", + user_timezone: "Asia/Kolkata", +}; + +const Profile: NextPage = () => { + const [isRemoving, setIsRemoving] = useState(false); + const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); + + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { + register, + handleSubmit, + reset, + watch, + setValue, + control, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + const { setToastAlert } = useToast(); + const { user: myProfile, mutateUser } = useUserAuth(); + + useEffect(() => { + reset({ ...defaultValues, ...myProfile }); + }, [myProfile, reset]); + + const onSubmit = async (formData: IUser) => { + if (formData.first_name === "" || formData.last_name === "") { + setToastAlert({ + type: "error", + title: "Error!", + message: "First and last names are required.", + }); + + return; + } + + const payload: Partial = { + first_name: formData.first_name, + last_name: formData.last_name, + avatar: formData.avatar, + cover_image: formData.cover_image, + role: formData.role, + display_name: formData.display_name, + user_timezone: formData.user_timezone, + }; + + await userService + .updateUser(payload) + .then((res) => { + mutateUser((prevData: any) => { + if (!prevData) return prevData; + + return { ...prevData, ...res }; + }, false); + setToastAlert({ + type: "success", + title: "Success!", + message: "Profile updated successfully.", + }); + }) + .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); + + fileService.deleteUserFile(url).then(() => { + if (updateUser) + userService + .updateUser({ avatar: "" }) + .then(() => { + setToastAlert({ + type: "success", + title: "Success!", + message: "Profile picture removed successfully.", + }); + mutateUser((prevData: any) => { + if (!prevData) return prevData; + return { ...prevData, avatar: "" }; + }, false); + setIsRemoving(false); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "There was some error in deleting your profile picture. Please try again.", + }); + }) + .finally(() => setIsRemoving(false)); + }); + }; + + const timeZoneOptions = TIME_ZONES.map((timeZone) => ({ + value: timeZone.value, + query: timeZone.label + " " + timeZone.value, + content: timeZone.label, + })); + + return ( + + + + } + > + setIsImageUploadModalOpen(false)} + isRemoving={isRemoving} + handleDelete={() => handleDelete(myProfile?.avatar, true)} + onSuccess={(url) => { + setValue("avatar", url); + handleSubmit(onSubmit)(); + setIsImageUploadModalOpen(false); + }} + value={watch("avatar") !== "" ? watch("avatar") : undefined} + userImage + /> + {myProfile ? ( +
+
+
+
+ {myProfile?.name +
+
+
+ +
+
+
+ +
+ ( + { + setValue("cover_image", imageUrl); + }} + value={ + watch("cover_image") ?? + "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab" + } + /> + )} + /> +
+
+ +
+
+
+ {`${watch("first_name")} ${watch("last_name")}`} +
+ {watch("email")} +
+ + + + + + + View Profile + + +
+ +
+
+

First Name

+ +
+ +
+

Last Name

+ +
+ +
+

Email

+ +
+ +
+

Role

+ ( + + {USER_ROLES.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.role && ( + Please select a role + )} +
+ +
+

Display name

+ + { + if (value.trim().length < 1) return "Display name can't be empty."; + + if (value.split(" ").length > 1) + return "Display name can't have two consecutive spaces."; + + if (value.replace(/\s/g, "").length < 1) + return "Display name must be at least 1 characters long."; + + if (value.replace(/\s/g, "").length > 20) + return "Display name must be less than 20 characters long."; + + return true; + }, + }} + /> +
+ +
+

Timezone

+ + ( + t.value === value)?.label ?? value + : "Select a timezone" + } + options={timeZoneOptions} + onChange={onChange} + verticalPosition="top" + optionsClassName="w-full" + input + /> + )} + /> + {errors.role && ( + Please select a role + )} +
+ +
+ + {isSubmitting ? "Updating Profile..." : "Update Profile"} + +
+
+
+
+
+ ) : ( +
+ +
+ )} +
+ ); +}; + +export default Profile; diff --git a/web/components/cycles/cycles-view.tsx b/web/components/cycles/cycles-view.tsx index 4eea43e6d0a..e3a886f066a 100644 --- a/web/components/cycles/cycles-view.tsx +++ b/web/components/cycles/cycles-view.tsx @@ -30,7 +30,7 @@ export const CyclesView: FC = observer((props) => { workspaceSlug && projectId && filter ? () => cycleStore.fetchCycles(workspaceSlug, projectId, filter) : null ); - const cyclesList = cycleStore.cycles?.[projectId]; + const cyclesList = cycleStore.projectCycles; return ( <> diff --git a/web/layouts/profile-layout/profile-sidebar.tsx b/web/layouts/profile-layout/profile-sidebar.tsx new file mode 100644 index 00000000000..fedf280106b --- /dev/null +++ b/web/layouts/profile-layout/profile-sidebar.tsx @@ -0,0 +1,34 @@ +// mobx react lite +import { observer } from "mobx-react-lite"; +import { SettingsSidebar } from "components/project/settings-sidebar"; +import { useState } from "react"; +import { Bars3Icon } from "@heroicons/react/24/outline"; + +const ProfileSidebar: React.FC<{}> = observer(() => { + const [toggleSidebar, setToggleSidebar] = useState(false) + + return ( +
+
+ +
+ +
+ ); +}); + +export default ProfileSidebar; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 21fd5fe8b49..da3e8593504 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -28,7 +28,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { const [createModal, setCreateModal] = useState(false); // store const { project: projectStore, cycle: cycleStore } = useMobxStore(); - const { currentProjectDetails } = projectStore; + const { projectCycles } = cycleStore // router const router = useRouter(); const { workspaceSlug, projectId, peekCycle } = router.query as { @@ -82,6 +82,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { const cycleView = cycleStore?.cycleView; const cycleLayout = cycleStore?.cycleLayout; + const totalCycles = projectCycles?.length ?? 0 return ( <> @@ -91,7 +92,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { isOpen={createModal} handleClose={() => setCreateModal(false)} /> - {currentProjectDetails?.total_cycles === 0 ? ( + {totalCycles === 0 ? (
Date: Mon, 6 Nov 2023 14:02:57 +0000 Subject: [PATCH 2/5] Delete \ --- "\\" | 391 ----------------------------------------------------------- 1 file changed, 391 deletions(-) delete mode 100644 "\\" diff --git "a/\\" "b/\\" deleted file mode 100644 index d50b2108a50..00000000000 --- "a/\\" +++ /dev/null @@ -1,391 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useRouter } from "next/router"; -import Link from "next/link"; - -// react-hook-form -import { Controller, useForm } from "react-hook-form"; -// services -import fileService from "services/file.service"; -import userService from "services/user.service"; -// hooks -import useUserAuth from "hooks/use-user-auth"; -import useToast from "hooks/use-toast"; -// layouts -import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -// components -import { ImagePickerPopover, ImageUploadModal } from "components/core"; -import { SettingsSidebar } from "components/project"; -// ui -import { CustomSearchSelect, CustomSelect, Input, PrimaryButton, Spinner } from "components/ui"; -import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -// icons -import { UserIcon } from "@heroicons/react/24/outline"; -import { UserCircle } from "lucide-react"; -// types -import type { NextPage } from "next"; -import type { IUser } from "types"; -// constants -import { USER_ROLES } from "constants/workspace"; -import { TIME_ZONES } from "constants/timezones"; - -const defaultValues: Partial = { - avatar: "", - cover_image: "", - first_name: "", - last_name: "", - email: "", - role: "Product / Project Manager", - user_timezone: "Asia/Kolkata", -}; - -const Profile: NextPage = () => { - const [isRemoving, setIsRemoving] = useState(false); - const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); - - const router = useRouter(); - const { workspaceSlug } = router.query; - - const { - register, - handleSubmit, - reset, - watch, - setValue, - control, - formState: { errors, isSubmitting }, - } = useForm({ defaultValues }); - - const { setToastAlert } = useToast(); - const { user: myProfile, mutateUser } = useUserAuth(); - - useEffect(() => { - reset({ ...defaultValues, ...myProfile }); - }, [myProfile, reset]); - - const onSubmit = async (formData: IUser) => { - if (formData.first_name === "" || formData.last_name === "") { - setToastAlert({ - type: "error", - title: "Error!", - message: "First and last names are required.", - }); - - return; - } - - const payload: Partial = { - first_name: formData.first_name, - last_name: formData.last_name, - avatar: formData.avatar, - cover_image: formData.cover_image, - role: formData.role, - display_name: formData.display_name, - user_timezone: formData.user_timezone, - }; - - await userService - .updateUser(payload) - .then((res) => { - mutateUser((prevData: any) => { - if (!prevData) return prevData; - - return { ...prevData, ...res }; - }, false); - setToastAlert({ - type: "success", - title: "Success!", - message: "Profile updated successfully.", - }); - }) - .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); - - fileService.deleteUserFile(url).then(() => { - if (updateUser) - userService - .updateUser({ avatar: "" }) - .then(() => { - setToastAlert({ - type: "success", - title: "Success!", - message: "Profile picture removed successfully.", - }); - mutateUser((prevData: any) => { - if (!prevData) return prevData; - return { ...prevData, avatar: "" }; - }, false); - setIsRemoving(false); - }) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "There was some error in deleting your profile picture. Please try again.", - }); - }) - .finally(() => setIsRemoving(false)); - }); - }; - - const timeZoneOptions = TIME_ZONES.map((timeZone) => ({ - value: timeZone.value, - query: timeZone.label + " " + timeZone.value, - content: timeZone.label, - })); - - return ( - - - - } - > - setIsImageUploadModalOpen(false)} - isRemoving={isRemoving} - handleDelete={() => handleDelete(myProfile?.avatar, true)} - onSuccess={(url) => { - setValue("avatar", url); - handleSubmit(onSubmit)(); - setIsImageUploadModalOpen(false); - }} - value={watch("avatar") !== "" ? watch("avatar") : undefined} - userImage - /> - {myProfile ? ( -
-
-
-
- {myProfile?.name -
-
-
- -
-
-
- -
- ( - { - setValue("cover_image", imageUrl); - }} - value={ - watch("cover_image") ?? - "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab" - } - /> - )} - /> -
-
- -
-
-
- {`${watch("first_name")} ${watch("last_name")}`} -
- {watch("email")} -
- - - - - - - View Profile - - -
- -
-
-

First Name

- -
- -
-

Last Name

- -
- -
-

Email

- -
- -
-

Role

- ( - - {USER_ROLES.map((item) => ( - - {item.label} - - ))} - - )} - /> - {errors.role && ( - Please select a role - )} -
- -
-

Display name

- - { - if (value.trim().length < 1) return "Display name can't be empty."; - - if (value.split(" ").length > 1) - return "Display name can't have two consecutive spaces."; - - if (value.replace(/\s/g, "").length < 1) - return "Display name must be at least 1 characters long."; - - if (value.replace(/\s/g, "").length > 20) - return "Display name must be less than 20 characters long."; - - return true; - }, - }} - /> -
- -
-

Timezone

- - ( - t.value === value)?.label ?? value - : "Select a timezone" - } - options={timeZoneOptions} - onChange={onChange} - verticalPosition="top" - optionsClassName="w-full" - input - /> - )} - /> - {errors.role && ( - Please select a role - )} -
- -
- - {isSubmitting ? "Updating Profile..." : "Update Profile"} - -
-
-
-
-
- ) : ( -
- -
- )} -
- ); -}; - -export default Profile; From df508297e8187141c53af6020d11894b74e31bba Mon Sep 17 00:00:00 2001 From: "onFire(Abhi)" <40654066+AbhiShake1@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:03:29 +0000 Subject: [PATCH 3/5] Delete web/layouts/profile-layout/profile-sidebar.tsx --- .../profile-layout/profile-sidebar.tsx | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 web/layouts/profile-layout/profile-sidebar.tsx diff --git a/web/layouts/profile-layout/profile-sidebar.tsx b/web/layouts/profile-layout/profile-sidebar.tsx deleted file mode 100644 index fedf280106b..00000000000 --- a/web/layouts/profile-layout/profile-sidebar.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// mobx react lite -import { observer } from "mobx-react-lite"; -import { SettingsSidebar } from "components/project/settings-sidebar"; -import { useState } from "react"; -import { Bars3Icon } from "@heroicons/react/24/outline"; - -const ProfileSidebar: React.FC<{}> = observer(() => { - const [toggleSidebar, setToggleSidebar] = useState(false) - - return ( -
-
- -
- -
- ); -}); - -export default ProfileSidebar; From 4a4649d6c69d43087a032f6acb6fd5cc3930d177 Mon Sep 17 00:00:00 2001 From: "onFire(Abhi)" <40654066+AbhiShake1@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:04:23 +0000 Subject: [PATCH 4/5] Update cycles.store.ts --- web/store/cycle/cycles.store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/store/cycle/cycles.store.ts b/web/store/cycle/cycles.store.ts index e9fcaee0364..0d4ff15f7fd 100644 --- a/web/store/cycle/cycles.store.ts +++ b/web/store/cycle/cycles.store.ts @@ -19,7 +19,7 @@ export interface ICycleStore { cycles: { [project_id: string]: ICycle[]; }; - projectCycles: ICycle[] | null; + projectCycles: ICycle[] | null; cycle_details: { [cycle_id: string]: ICycle; }; From c2996215da4e35e3b62dfc4d640ea4b15de8af07 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:04:02 +0530 Subject: [PATCH 5/5] fix: remove duplicate type declaration --- web/store/cycle/cycles.store.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web/store/cycle/cycles.store.ts b/web/store/cycle/cycles.store.ts index ad52a01fb8f..04832684143 100644 --- a/web/store/cycle/cycles.store.ts +++ b/web/store/cycle/cycles.store.ts @@ -22,7 +22,6 @@ export interface ICycleStore { [filterType: string]: ICycle[]; }; }; - projectCycles: ICycle[] | null; cycle_details: { [cycleId: string]: ICycle; };