fix: bug and auth fixes (#1224)

* fix: sign in and invitation page fixes

* fix: project and workspace services track event fix

* fix: user onboarding complete track event fix

* fix: issue track event fix

* fix: partial property , issue comment and mark as done issue track event fix

* fix: bulk delete , move to cycle or module and issue label track event fix

* fix: state , cycle and module track event fix

* fix: pages and block track event fix

* fix: integration , estimate , importer , analytics and gpt track event fix

* fix: view track event fix

* fix: build fix

* fix: build fix
This commit is contained in:
Anmol Singh Bhatia 2023-06-06 21:36:00 +05:30 committed by GitHub
parent c127353281
commit 6f2a38ad66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 1319 additions and 494 deletions

View File

@ -18,7 +18,7 @@ import { Loader, PrimaryButton } from "components/ui";
// helpers // helpers
import { convertResponseToBarGraphData } from "helpers/analytics.helper"; import { convertResponseToBarGraphData } from "helpers/analytics.helper";
// types // types
import { IAnalyticsParams, IAnalyticsResponse } from "types"; import { IAnalyticsParams, IAnalyticsResponse, ICurrentUserResponse } from "types";
// fetch-keys // fetch-keys
import { ANALYTICS } from "constants/fetch-keys"; import { ANALYTICS } from "constants/fetch-keys";
@ -29,6 +29,7 @@ type Props = {
control: Control<IAnalyticsParams, any>; control: Control<IAnalyticsParams, any>;
setValue: UseFormSetValue<IAnalyticsParams>; setValue: UseFormSetValue<IAnalyticsParams>;
fullScreen: boolean; fullScreen: boolean;
user: ICurrentUserResponse | undefined;
}; };
export const CustomAnalytics: React.FC<Props> = ({ export const CustomAnalytics: React.FC<Props> = ({
@ -38,6 +39,7 @@ export const CustomAnalytics: React.FC<Props> = ({
control, control,
setValue, setValue,
fullScreen, fullScreen,
user,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -124,6 +126,7 @@ export const CustomAnalytics: React.FC<Props> = ({
params={params} params={params}
fullScreen={fullScreen} fullScreen={fullScreen}
isProjectLevel={isProjectLevel} isProjectLevel={isProjectLevel}
user={user}
/> />
</div> </div>
); );

View File

@ -27,6 +27,7 @@ import { renderShortDate } from "helpers/date-time.helper";
import { import {
IAnalyticsParams, IAnalyticsParams,
IAnalyticsResponse, IAnalyticsResponse,
ICurrentUserResponse,
IExportAnalyticsFormData, IExportAnalyticsFormData,
IProject, IProject,
IWorkspace, IWorkspace,
@ -41,6 +42,7 @@ type Props = {
params: IAnalyticsParams; params: IAnalyticsParams;
fullScreen: boolean; fullScreen: boolean;
isProjectLevel: boolean; isProjectLevel: boolean;
user: ICurrentUserResponse | undefined;
}; };
export const AnalyticsSidebar: React.FC<Props> = ({ export const AnalyticsSidebar: React.FC<Props> = ({
@ -48,6 +50,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
params, params,
fullScreen, fullScreen,
isProjectLevel = false, isProjectLevel = false,
user,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
@ -138,7 +141,8 @@ export const AnalyticsSidebar: React.FC<Props> = ({
? "MODULE_ANALYTICS_EXPORT" ? "MODULE_ANALYTICS_EXPORT"
: projectId : projectId
? "PROJECT_ANALYTICS_EXPORT" ? "PROJECT_ANALYTICS_EXPORT"
: "WORKSPACE_ANALYTICS_EXPORT" : "WORKSPACE_ANALYTICS_EXPORT",
user
); );
}; };

View File

@ -26,6 +26,7 @@ import {
import { IAnalyticsParams, IWorkspace } from "types"; import { IAnalyticsParams, IWorkspace } from "types";
// fetch-keys // fetch-keys
import { ANALYTICS, CYCLE_DETAILS, MODULE_DETAILS, PROJECT_DETAILS } from "constants/fetch-keys"; import { ANALYTICS, CYCLE_DETAILS, MODULE_DETAILS, PROJECT_DETAILS } from "constants/fetch-keys";
import useUserAuth from "hooks/use-user-auth";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -47,6 +48,8 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
const { user } = useUserAuth();
const { control, watch, setValue } = useForm<IAnalyticsParams>({ defaultValues }); const { control, watch, setValue } = useForm<IAnalyticsParams>({ defaultValues });
const params: IAnalyticsParams = { const params: IAnalyticsParams = {
@ -136,7 +139,8 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
trackEventServices.trackAnalyticsEvent( trackEventServices.trackAnalyticsEvent(
eventPayload, eventPayload,
cycleId ? `CYCLE_${eventType}` : moduleId ? `MODULE_${eventType}` : `PROJECT_${eventType}` cycleId ? `CYCLE_${eventType}` : moduleId ? `MODULE_${eventType}` : `PROJECT_${eventType}`,
user
); );
}; };
@ -210,6 +214,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
control={control} control={control}
setValue={setValue} setValue={setValue}
fullScreen={fullScreen} fullScreen={fullScreen}
user={user}
/> />
</Tab.Panel> </Tab.Panel>
</Tab.Panels> </Tab.Panels>

View File

@ -7,7 +7,7 @@ import { Command } from "cmdk";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// constants // constants
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, PROJECT_MEMBERS } from "constants/fetch-keys"; import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, PROJECT_MEMBERS } from "constants/fetch-keys";
// icons // icons
@ -18,9 +18,10 @@ import { Avatar } from "components/ui";
type Props = { type Props = {
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>; setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
issue: IIssue; issue: IIssue;
user: ICurrentUserResponse | undefined;
}; };
export const ChangeIssueAssignee: React.FC<Props> = ({ setIsPaletteOpen, issue }) => { export const ChangeIssueAssignee: React.FC<Props> = ({ setIsPaletteOpen, issue, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
@ -71,7 +72,7 @@ export const ChangeIssueAssignee: React.FC<Props> = ({ setIsPaletteOpen, issue }
const payload = { ...formData }; const payload = { ...formData };
await issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.then(() => { .then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
}) })

View File

@ -7,7 +7,7 @@ import { Command } from "cmdk";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// constants // constants
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
import { PRIORITIES } from "constants/project"; import { PRIORITIES } from "constants/project";
@ -17,9 +17,10 @@ import { CheckIcon, getPriorityIcon } from "components/icons";
type Props = { type Props = {
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>; setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
issue: IIssue; issue: IIssue;
user: ICurrentUserResponse;
}; };
export const ChangeIssuePriority: React.FC<Props> = ({ setIsPaletteOpen, issue }) => { export const ChangeIssuePriority: React.FC<Props> = ({ setIsPaletteOpen, issue, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
@ -42,7 +43,7 @@ export const ChangeIssuePriority: React.FC<Props> = ({ setIsPaletteOpen, issue }
const payload = { ...formData }; const payload = { ...formData };
await issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.then(() => { .then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
}) })

View File

@ -12,7 +12,7 @@ import { getStatesList } from "helpers/state.helper";
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
import stateService from "services/state.service"; import stateService from "services/state.service";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch keys // fetch keys
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, STATES_LIST } from "constants/fetch-keys"; import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, STATES_LIST } from "constants/fetch-keys";
// icons // icons
@ -21,9 +21,10 @@ import { CheckIcon, getStateGroupIcon } from "components/icons";
type Props = { type Props = {
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>; setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
issue: IIssue; issue: IIssue;
user: ICurrentUserResponse | undefined;
}; };
export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue }) => { export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
@ -53,7 +54,7 @@ export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue }) =
const payload = { ...formData }; const payload = { ...formData };
await issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.then(() => { .then(() => {
mutateIssueDetails(); mutateIssueDetails();
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));

View File

@ -136,7 +136,7 @@ export const CommandPalette: React.FC = () => {
const payload = { ...formData }; const payload = { ...formData };
await issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.then(() => { .then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
mutate(ISSUE_DETAILS(issueId as string)); mutate(ISSUE_DETAILS(issueId as string));
@ -330,25 +330,33 @@ export const CommandPalette: React.FC = () => {
<> <>
<ShortcutsModal isOpen={isShortcutsModalOpen} setIsOpen={setIsShortcutsModalOpen} /> <ShortcutsModal isOpen={isShortcutsModalOpen} setIsOpen={setIsShortcutsModalOpen} />
{workspaceSlug && ( {workspaceSlug && (
<CreateProjectModal isOpen={isProjectModalOpen} setIsOpen={setIsProjectModalOpen} /> <CreateProjectModal
isOpen={isProjectModalOpen}
setIsOpen={setIsProjectModalOpen}
user={user}
/>
)} )}
{projectId && ( {projectId && (
<> <>
<CreateUpdateCycleModal <CreateUpdateCycleModal
isOpen={isCreateCycleModalOpen} isOpen={isCreateCycleModalOpen}
handleClose={() => setIsCreateCycleModalOpen(false)} handleClose={() => setIsCreateCycleModalOpen(false)}
user={user}
/> />
<CreateUpdateModuleModal <CreateUpdateModuleModal
isOpen={isCreateModuleModalOpen} isOpen={isCreateModuleModalOpen}
setIsOpen={setIsCreateModuleModalOpen} setIsOpen={setIsCreateModuleModalOpen}
user={user}
/> />
<CreateUpdateViewModal <CreateUpdateViewModal
handleClose={() => setIsCreateViewModalOpen(false)} handleClose={() => setIsCreateViewModalOpen(false)}
isOpen={isCreateViewModalOpen} isOpen={isCreateViewModalOpen}
user={user}
/> />
<CreateUpdatePageModal <CreateUpdatePageModal
isOpen={isCreateUpdatePageModalOpen} isOpen={isCreateUpdatePageModalOpen}
handleClose={() => setIsCreateUpdatePageModalOpen(false)} handleClose={() => setIsCreateUpdatePageModalOpen(false)}
user={user}
/> />
</> </>
)} )}
@ -357,6 +365,7 @@ export const CommandPalette: React.FC = () => {
handleClose={() => setDeleteIssueModal(false)} handleClose={() => setDeleteIssueModal(false)}
isOpen={deleteIssueModal} isOpen={deleteIssueModal}
data={issueDetails} data={issueDetails}
user={user}
/> />
)} )}
@ -367,6 +376,7 @@ export const CommandPalette: React.FC = () => {
<BulkDeleteIssuesModal <BulkDeleteIssuesModal
isOpen={isBulkDeleteIssuesModalOpen} isOpen={isBulkDeleteIssuesModalOpen}
setIsOpen={setIsBulkDeleteIssuesModalOpen} setIsOpen={setIsBulkDeleteIssuesModalOpen}
user={user}
/> />
<Transition.Root <Transition.Root
show={isPaletteOpen} show={isPaletteOpen}
@ -854,6 +864,7 @@ export const CommandPalette: React.FC = () => {
<ChangeIssueState <ChangeIssueState
issue={issueDetails} issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen} setIsPaletteOpen={setIsPaletteOpen}
user={user}
/> />
</> </>
)} )}
@ -861,12 +872,14 @@ export const CommandPalette: React.FC = () => {
<ChangeIssuePriority <ChangeIssuePriority
issue={issueDetails} issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen} setIsPaletteOpen={setIsPaletteOpen}
user={user}
/> />
)} )}
{page === "change-issue-assignee" && issueDetails && ( {page === "change-issue-assignee" && issueDetails && (
<ChangeIssueAssignee <ChangeIssueAssignee
issue={issueDetails} issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen} setIsPaletteOpen={setIsPaletteOpen}
user={user}
/> />
)} )}
{page === "change-interface-theme" && ( {page === "change-interface-theme" && (

View File

@ -5,7 +5,7 @@ import { SingleBoard } from "components/core/board-view/single-board";
// helpers // helpers
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
// types // types
import { IIssue, IState, UserAuth } from "types"; import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types";
import { getStateGroupIcon } from "components/icons"; import { getStateGroupIcon } from "components/icons";
type Props = { type Props = {
@ -19,6 +19,7 @@ type Props = {
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
removeIssue: ((bridgeId: string, issueId: string) => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -33,6 +34,7 @@ export const AllBoards: React.FC<Props> = ({
handleTrashBox, handleTrashBox,
removeIssue, removeIssue,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
const { const {
@ -65,6 +67,7 @@ export const AllBoards: React.FC<Props> = ({
handleTrashBox={handleTrashBox} handleTrashBox={handleTrashBox}
removeIssue={removeIssue} removeIssue={removeIssue}
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={userAuth} userAuth={userAuth}
/> />
); );

View File

@ -17,7 +17,7 @@ import { PlusIcon } from "@heroicons/react/24/outline";
// helpers // helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types // types
import { IIssue, IState, UserAuth } from "types"; import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types";
type Props = { type Props = {
type?: "issue" | "cycle" | "module"; type?: "issue" | "cycle" | "module";
@ -31,6 +31,7 @@ type Props = {
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
removeIssue: ((bridgeId: string, issueId: string) => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -46,6 +47,7 @@ export const SingleBoard: React.FC<Props> = ({
handleTrashBox, handleTrashBox,
removeIssue, removeIssue,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
// collapse/expand // collapse/expand
@ -129,6 +131,7 @@ export const SingleBoard: React.FC<Props> = ({
removeIssue(issue.bridge_id, issue.id); removeIssue(issue.bridge_id, issue.id);
}} }}
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={userAuth} userAuth={userAuth}
/> />
)} )}

View File

@ -44,7 +44,7 @@ import { LayerDiagonalIcon } from "components/icons";
import { handleIssuesMutation } from "constants/issue"; import { handleIssuesMutation } from "constants/issue";
import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper";
// types // types
import { IIssue, Properties, TIssueGroupByOptions, UserAuth } from "types"; import { ICurrentUserResponse, IIssue, Properties, TIssueGroupByOptions, UserAuth } from "types";
// fetch-keys // fetch-keys
import { import {
CYCLE_DETAILS, CYCLE_DETAILS,
@ -69,6 +69,7 @@ type Props = {
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -87,6 +88,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
handleDeleteIssue, handleDeleteIssue,
handleTrashBox, handleTrashBox,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
// context menu // context menu
@ -170,7 +172,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
} }
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId, formData) .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user)
.then(() => { .then(() => {
if (cycleId) { if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
@ -342,6 +344,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
user={user}
selfPositioned selfPositioned
/> />
)} )}
@ -350,6 +353,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
user={user}
selfPositioned selfPositioned
/> />
)} )}
@ -357,6 +361,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
<ViewDueDateSelect <ViewDueDateSelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -384,6 +389,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
tooltipPosition="left" tooltipPosition="left"
user={user}
selfPositioned selfPositioned
/> />
)} )}
@ -392,6 +398,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
user={user}
selfPositioned selfPositioned
/> />
)} )}

View File

@ -18,7 +18,7 @@ import { DangerButton, SecondaryButton } from "components/ui";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons"; import { LayerDiagonalIcon } from "components/icons";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch keys // fetch keys
import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; import { PROJECT_ISSUES_LIST } from "constants/fetch-keys";
@ -29,9 +29,10 @@ type FormInput = {
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
user: ICurrentUserResponse | undefined;
}; };
export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => { export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user }) => {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const router = useRouter(); const router = useRouter();
@ -91,9 +92,14 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
if (workspaceSlug && projectId) { if (workspaceSlug && projectId) {
await issuesServices await issuesServices
.bulkDeleteIssues(workspaceSlug as string, projectId as string, { .bulkDeleteIssues(
issue_ids: data.delete_issue_ids, workspaceSlug as string,
}) projectId as string,
{
issue_ids: data.delete_issue_ids,
},
user
)
.then((res) => { .then((res) => {
setToastAlert({ setToastAlert({
title: "Success", title: "Success",

View File

@ -24,7 +24,7 @@ import {
formatDate, formatDate,
} from "helpers/calendar.helper"; } from "helpers/calendar.helper";
// types // types
import { ICalendarRange, IIssue, UserAuth } from "types"; import { ICalendarRange, ICurrentUserResponse, IIssue, UserAuth } from "types";
// fetch-keys // fetch-keys
import { import {
CYCLE_ISSUES_WITH_PARAMS, CYCLE_ISSUES_WITH_PARAMS,
@ -38,6 +38,7 @@ type Props = {
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
addIssueToDate: (date: string) => void; addIssueToDate: (date: string) => void;
isCompleted: boolean; isCompleted: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -46,6 +47,7 @@ export const CalendarView: React.FC<Props> = ({
handleDeleteIssue, handleDeleteIssue,
addIssueToDate, addIssueToDate,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
const [showWeekEnds, setShowWeekEnds] = useState(false); const [showWeekEnds, setShowWeekEnds] = useState(false);
@ -134,9 +136,15 @@ export const CalendarView: React.FC<Props> = ({
); );
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, draggableId, { .patchIssue(
target_date: destination?.droppableId, workspaceSlug as string,
}) projectId as string,
draggableId,
{
target_date: destination?.droppableId,
},
user
)
.then(() => mutate(fetchKey)); .then(() => mutate(fetchKey));
}; };
@ -219,6 +227,7 @@ export const CalendarView: React.FC<Props> = ({
addIssueToDate={addIssueToDate} addIssueToDate={addIssueToDate}
isMonthlyView={isMonthlyView} isMonthlyView={isMonthlyView}
showWeekEnds={showWeekEnds} showWeekEnds={showWeekEnds}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
))} ))}

View File

@ -10,7 +10,7 @@ import { PlusSmallIcon } from "@heroicons/react/24/outline";
// helper // helper
import { formatDate } from "helpers/calendar.helper"; import { formatDate } from "helpers/calendar.helper";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
type Props = { type Props = {
handleEditIssue: (issue: IIssue) => void; handleEditIssue: (issue: IIssue) => void;
@ -23,6 +23,7 @@ type Props = {
addIssueToDate: (date: string) => void; addIssueToDate: (date: string) => void;
isMonthlyView: boolean; isMonthlyView: boolean;
showWeekEnds: boolean; showWeekEnds: boolean;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -34,6 +35,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
addIssueToDate, addIssueToDate,
isMonthlyView, isMonthlyView,
showWeekEnds, showWeekEnds,
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const [showAllIssues, setShowAllIssues] = useState(false); const [showAllIssues, setShowAllIssues] = useState(false);
@ -72,6 +74,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
issue={issue} issue={issue}
handleEditIssue={handleEditIssue} handleEditIssue={handleEditIssue}
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}

View File

@ -28,7 +28,7 @@ import { LayerDiagonalIcon } from "components/icons";
// helper // helper
import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper";
// type // type
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch-keys // fetch-keys
import { import {
CYCLE_ISSUES_WITH_PARAMS, CYCLE_ISSUES_WITH_PARAMS,
@ -44,6 +44,7 @@ type Props = {
provided: DraggableProvided; provided: DraggableProvided;
snapshot: DraggableStateSnapshot; snapshot: DraggableStateSnapshot;
issue: IIssue; issue: IIssue;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -54,6 +55,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
provided, provided,
snapshot, snapshot,
issue, issue,
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -95,7 +97,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
); );
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData, user)
.then(() => { .then(() => {
mutate(fetchKey); mutate(fetchKey);
}) })
@ -183,6 +185,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="left" position="left"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -192,6 +195,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="left" position="left"
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
user={user}
/> />
)} )}
@ -199,6 +203,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
<ViewDueDateSelect <ViewDueDateSelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -227,6 +232,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="left" position="left"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -235,6 +241,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="left" position="left"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}

View File

@ -10,6 +10,7 @@ import aiService from "services/ai.service";
import trackEventServices from "services/track-event.service"; import trackEventServices from "services/track-event.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui // ui
import { Input, PrimaryButton, SecondaryButton } from "components/ui"; import { Input, PrimaryButton, SecondaryButton } from "components/ui";
@ -60,6 +61,8 @@ export const GptAssistantModal: React.FC<Props> = ({
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
const editorRef = useRef<any>(null); const editorRef = useRef<any>(null);
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -97,10 +100,15 @@ export const GptAssistantModal: React.FC<Props> = ({
} }
await aiService await aiService
.createGptTask(workspaceSlug as string, projectId as string, { .createGptTask(
prompt: content && content !== "" ? content : htmlContent ?? "", workspaceSlug as string,
task: formData.task, projectId as string,
}) {
prompt: content && content !== "" ? content : htmlContent ?? "",
task: formData.task,
},
user
)
.then((res) => { .then((res) => {
setResponse(res.response_html); setResponse(res.response_html);
setFocus("task"); setFocus("task");
@ -190,10 +198,15 @@ export const GptAssistantModal: React.FC<Props> = ({
if (block) if (block)
trackEventServices.trackUseGPTResponseEvent( trackEventServices.trackUseGPTResponseEvent(
block, block,
"USE_GPT_RESPONSE_IN_PAGE_BLOCK" "USE_GPT_RESPONSE_IN_PAGE_BLOCK",
user
); );
else if (issue) else if (issue)
trackEventServices.trackUseGPTResponseEvent(issue, "USE_GPT_RESPONSE_IN_ISSUE"); trackEventServices.trackUseGPTResponseEvent(
issue,
"USE_GPT_RESPONSE_IN_ISSUE",
user
);
}} }}
> >
Use this response Use this response

View File

@ -17,6 +17,7 @@ import { useProjectMyMembership } from "contexts/project-member.context";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view"; import useIssuesView from "hooks/use-issues-view";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { AllLists, AllBoards, FilterList, CalendarView, GanttChartView } from "components/core"; import { AllLists, AllBoards, FilterList, CalendarView, GanttChartView } from "components/core";
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
@ -89,6 +90,8 @@ export const IssuesView: React.FC<Props> = ({
const { memberRole } = useProjectMyMembership(); const { memberRole } = useProjectMyMembership();
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { const {
@ -220,11 +223,17 @@ export const IssuesView: React.FC<Props> = ({
// patch request // patch request
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { .patchIssue(
priority: draggedItem.priority, workspaceSlug as string,
state: draggedItem.state, projectId as string,
sort_order: draggedItem.sort_order, draggedItem.id,
}) {
priority: draggedItem.priority,
state: draggedItem.state,
sort_order: draggedItem.sort_order,
},
user
)
.then((response) => { .then((response) => {
const sourceStateBeforeDrag = states.find((state) => state.name === source.droppableId); const sourceStateBeforeDrag = states.find((state) => state.name === source.droppableId);
@ -232,14 +241,17 @@ export const IssuesView: React.FC<Props> = ({
sourceStateBeforeDrag?.group !== "completed" && sourceStateBeforeDrag?.group !== "completed" &&
response?.state_detail?.group === "completed" response?.state_detail?.group === "completed"
) )
trackEventServices.trackIssueMarkedAsDoneEvent({ trackEventServices.trackIssueMarkedAsDoneEvent(
workspaceSlug, {
workspaceId: draggedItem.workspace, workspaceSlug,
projectName: draggedItem.project_detail.name, workspaceId: draggedItem.workspace,
projectIdentifier: draggedItem.project_detail.identifier, projectName: draggedItem.project_detail.name,
projectId, projectIdentifier: draggedItem.project_detail.identifier,
issueId: draggedItem.id, projectId,
}); issueId: draggedItem.id,
},
user
);
if (cycleId) { if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
@ -419,6 +431,7 @@ export const IssuesView: React.FC<Props> = ({
isOpen={createViewModal !== null} isOpen={createViewModal !== null}
handleClose={() => setCreateViewModal(null)} handleClose={() => setCreateViewModal(null)}
preLoadedData={createViewModal} preLoadedData={createViewModal}
user={user}
/> />
<CreateUpdateIssueModal <CreateUpdateIssueModal
isOpen={createIssueModal && preloadedData?.actionType === "createIssue"} isOpen={createIssueModal && preloadedData?.actionType === "createIssue"}
@ -437,6 +450,7 @@ export const IssuesView: React.FC<Props> = ({
handleClose={() => setDeleteIssueModal(false)} handleClose={() => setDeleteIssueModal(false)}
isOpen={deleteIssueModal} isOpen={deleteIssueModal}
data={issueToDelete} data={issueToDelete}
user={user}
/> />
<TransferIssuesModal <TransferIssuesModal
handleClose={() => setTransferIssuesModal(false)} handleClose={() => setTransferIssuesModal(false)}
@ -508,6 +522,7 @@ export const IssuesView: React.FC<Props> = ({
: null : null
} }
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={memberRole} userAuth={memberRole}
/> />
) : issueView === "kanban" ? ( ) : issueView === "kanban" ? (
@ -528,6 +543,7 @@ export const IssuesView: React.FC<Props> = ({
: null : null
} }
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={memberRole} userAuth={memberRole}
/> />
) : issueView === "calendar" ? ( ) : issueView === "calendar" ? (
@ -536,6 +552,7 @@ export const IssuesView: React.FC<Props> = ({
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
addIssueToDate={addIssueToDate} addIssueToDate={addIssueToDate}
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={memberRole} userAuth={memberRole}
/> />
) : ( ) : (

View File

@ -3,7 +3,7 @@ import useIssuesView from "hooks/use-issues-view";
// components // components
import { SingleList } from "components/core/list-view/single-list"; import { SingleList } from "components/core/list-view/single-list";
// types // types
import { IIssue, IState, UserAuth } from "types"; import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types";
// types // types
type Props = { type Props = {
@ -16,6 +16,7 @@ type Props = {
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -29,6 +30,7 @@ export const AllLists: React.FC<Props> = ({
handleDeleteIssue, handleDeleteIssue,
removeIssue, removeIssue,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
const { groupedByIssues, groupByProperty: selectedGroup, showEmptyGroups } = useIssuesView(); const { groupedByIssues, groupByProperty: selectedGroup, showEmptyGroups } = useIssuesView();
@ -58,6 +60,7 @@ export const AllLists: React.FC<Props> = ({
openIssuesListModal={type !== "issue" ? openIssuesListModal : null} openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
removeIssue={removeIssue} removeIssue={removeIssue}
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={userAuth} userAuth={userAuth}
/> />
); );

View File

@ -36,7 +36,7 @@ import { LayerDiagonalIcon } from "components/icons";
import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper";
import { handleIssuesMutation } from "constants/issue"; import { handleIssuesMutation } from "constants/issue";
// types // types
import { IIssue, Properties, UserAuth } from "types"; import { ICurrentUserResponse, IIssue, Properties, UserAuth } from "types";
// fetch-keys // fetch-keys
import { import {
CYCLE_DETAILS, CYCLE_DETAILS,
@ -57,6 +57,7 @@ type Props = {
removeIssue?: (() => void) | null; removeIssue?: (() => void) | null;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -71,6 +72,7 @@ export const SingleListIssue: React.FC<Props> = ({
groupTitle, groupTitle,
handleDeleteIssue, handleDeleteIssue,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
// context menu // context menu
@ -141,7 +143,7 @@ export const SingleListIssue: React.FC<Props> = ({
); );
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId, formData) .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user)
.then(() => { .then(() => {
if (cycleId) { if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
@ -241,6 +243,7 @@ export const SingleListIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="right" position="right"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -249,6 +252,7 @@ export const SingleListIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="right" position="right"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -256,6 +260,7 @@ export const SingleListIssue: React.FC<Props> = ({
<ViewDueDateSelect <ViewDueDateSelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -284,6 +289,7 @@ export const SingleListIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="right" position="right"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -292,6 +298,7 @@ export const SingleListIssue: React.FC<Props> = ({
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
position="right" position="right"
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}

View File

@ -19,7 +19,14 @@ import { getPriorityIcon, getStateGroupIcon } from "components/icons";
// helpers // helpers
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
// types // types
import { IIssue, IIssueLabels, IState, TIssueGroupByOptions, UserAuth } from "types"; import {
ICurrentUserResponse,
IIssue,
IIssueLabels,
IState,
TIssueGroupByOptions,
UserAuth,
} from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys"; import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys";
@ -39,6 +46,7 @@ type Props = {
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null;
isCompleted?: boolean; isCompleted?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -56,6 +64,7 @@ export const SingleList: React.FC<Props> = ({
openIssuesListModal, openIssuesListModal,
removeIssue, removeIssue,
isCompleted = false, isCompleted = false,
user,
userAuth, userAuth,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -208,6 +217,7 @@ export const SingleList: React.FC<Props> = ({
removeIssue(issue.bridge_id, issue.id); removeIssue(issue.bridge_id, issue.id);
}} }}
isCompleted={isCompleted} isCompleted={isCompleted}
user={user}
userAuth={userAuth} userAuth={userAuth}
/> />
)) ))

View File

@ -8,6 +8,7 @@ import { mutate } from "swr";
import cyclesService from "services/cycles.service"; import cyclesService from "services/cycles.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { import {
CreateUpdateCycleModal, CreateUpdateCycleModal,
@ -48,6 +49,7 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const handleEditCycle = (cycle: ICycle) => { const handleEditCycle = (cycle: ICycle) => {
@ -158,11 +160,13 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
isOpen={createUpdateCycleModal} isOpen={createUpdateCycleModal}
handleClose={() => setCreateUpdateCycleModal(false)} handleClose={() => setCreateUpdateCycleModal(false)}
data={selectedCycleToUpdate} data={selectedCycleToUpdate}
user={user}
/> />
<DeleteCycleModal <DeleteCycleModal
isOpen={deleteCycleModal} isOpen={deleteCycleModal}
setIsOpen={setDeleteCycleModal} setIsOpen={setDeleteCycleModal}
data={selectedCycleToDelete} data={selectedCycleToDelete}
user={user}
/> />
{cycles ? ( {cycles ? (
cycles.length > 0 ? ( cycles.length > 0 ? (

View File

@ -14,11 +14,12 @@ import { DangerButton, SecondaryButton } from "components/ui";
// icons // icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types // types
import type { ICycle } from "types"; import type { ICurrentUserResponse, ICycle } from "types";
type TConfirmCycleDeletionProps = { type TConfirmCycleDeletionProps = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data?: ICycle | null; data?: ICycle | null;
user: ICurrentUserResponse | undefined;
}; };
// fetch-keys // fetch-keys
import { import {
@ -34,6 +35,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
isOpen, isOpen,
setIsOpen, setIsOpen,
data, data,
user,
}) => { }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
@ -53,7 +55,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
setIsDeleteLoading(true); setIsDeleteLoading(true);
await cycleService await cycleService
.deleteCycle(workspaceSlug as string, data.project, data.id) .deleteCycle(workspaceSlug as string, data.project, data.id, user)
.then(() => { .then(() => {
const cycleType = getDateRangeStatus(data.start_date, data.end_date); const cycleType = getDateRangeStatus(data.start_date, data.end_date);
const fetchKey = const fetchKey =

View File

@ -15,7 +15,7 @@ import { CycleForm } from "components/cycles";
// helper // helper
import { getDateRangeStatus, isDateGreaterThanToday } from "helpers/date-time.helper"; import { getDateRangeStatus, isDateGreaterThanToday } from "helpers/date-time.helper";
// types // types
import type { ICycle } from "types"; import type { ICurrentUserResponse, ICycle } from "types";
// fetch keys // fetch keys
import { import {
COMPLETED_CYCLES_LIST, COMPLETED_CYCLES_LIST,
@ -30,12 +30,14 @@ type CycleModalProps = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
data?: ICycle | null; data?: ICycle | null;
user: ICurrentUserResponse | undefined;
}; };
export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
isOpen, isOpen,
handleClose, handleClose,
data, data,
user,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -46,7 +48,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await cycleService await cycleService
.createCycle(workspaceSlug.toString(), projectId.toString(), payload) .createCycle(workspaceSlug.toString(), projectId.toString(), payload, user)
.then((res) => { .then((res) => {
switch (getDateRangeStatus(res.start_date, res.end_date)) { switch (getDateRangeStatus(res.start_date, res.end_date)) {
case "completed": case "completed":
@ -84,7 +86,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await cycleService await cycleService
.updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload) .updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload, user)
.then((res) => { .then((res) => {
switch (getDateRangeStatus(data?.start_date, data?.end_date)) { switch (getDateRangeStatus(data?.start_date, data?.end_date)) {
case "completed": case "completed":

View File

@ -4,6 +4,7 @@ import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
import useUserAuth from "hooks/use-user-auth";
// headless ui // headless ui
import { Listbox, Transition } from "@headlessui/react"; import { Listbox, Transition } from "@headlessui/react";
// icons // icons
@ -35,6 +36,8 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
const { data: cycles } = useSWR( const { data: cycles } = useSWR(
workspaceSlug && projectId ? CYCLES_LIST(projectId) : null, workspaceSlug && projectId ? CYCLES_LIST(projectId) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -54,7 +57,11 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
return ( return (
<> <>
<CreateUpdateCycleModal isOpen={isCycleModalActive} handleClose={closeCycleModal} /> <CreateUpdateCycleModal
isOpen={isCycleModalActive}
handleClose={closeCycleModal}
user={user}
/>
<Listbox as="div" className="relative" value={value} onChange={onChange} multiple={multiple}> <Listbox as="div" className="relative" value={value} onChange={onChange} multiple={multiple}>
{({ open }) => ( {({ open }) => (
<> <>

View File

@ -39,7 +39,7 @@ import {
renderShortDate, renderShortDate,
} from "helpers/date-time.helper"; } from "helpers/date-time.helper";
// types // types
import { ICycle, IIssue } from "types"; import { ICurrentUserResponse, ICycle, IIssue } from "types";
// fetch-keys // fetch-keys
import { CYCLE_DETAILS, CYCLE_ISSUES } from "constants/fetch-keys"; import { CYCLE_DETAILS, CYCLE_ISSUES } from "constants/fetch-keys";
@ -48,6 +48,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
cycleStatus: string; cycleStatus: string;
isCompleted: boolean; isCompleted: boolean;
user: ICurrentUserResponse | undefined;
}; };
export const CycleDetailsSidebar: React.FC<Props> = ({ export const CycleDetailsSidebar: React.FC<Props> = ({
@ -55,6 +56,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
isOpen, isOpen,
cycleStatus, cycleStatus,
isCompleted, isCompleted,
user,
}) => { }) => {
const [cycleDeleteModal, setCycleDeleteModal] = useState(false); const [cycleDeleteModal, setCycleDeleteModal] = useState(false);
@ -94,7 +96,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
); );
cyclesService cyclesService
.patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data) .patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data, user)
.then(() => mutate(CYCLE_DETAILS(cycleId as string))) .then(() => mutate(CYCLE_DETAILS(cycleId as string)))
.catch((e) => console.log(e)); .catch((e) => console.log(e));
}; };
@ -294,7 +296,12 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
return ( return (
<> <>
<DeleteCycleModal isOpen={cycleDeleteModal} setIsOpen={setCycleDeleteModal} data={cycle} /> <DeleteCycleModal
isOpen={cycleDeleteModal}
setIsOpen={setCycleDeleteModal}
data={cycle}
user={user}
/>
<div <div
className={`fixed top-[66px] ${ className={`fixed top-[66px] ${
isOpen ? "right-0" : "-right-[24rem]" isOpen ? "right-0" : "-right-[24rem]"

View File

@ -17,7 +17,7 @@ import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// helpers // helpers
import { checkDuplicates } from "helpers/array.helper"; import { checkDuplicates } from "helpers/array.helper";
// types // types
import { IEstimate, IEstimateFormData } from "types"; import { ICurrentUserResponse, IEstimate, IEstimateFormData } from "types";
// fetch-keys // fetch-keys
import { ESTIMATES_LIST, ESTIMATE_DETAILS } from "constants/fetch-keys"; import { ESTIMATES_LIST, ESTIMATE_DETAILS } from "constants/fetch-keys";
@ -25,6 +25,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
data?: IEstimate; data?: IEstimate;
user: ICurrentUserResponse | undefined;
}; };
type FormValues = { type FormValues = {
@ -49,7 +50,7 @@ const defaultValues: Partial<FormValues> = {
value6: "", value6: "",
}; };
export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data, isOpen }) => { export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data, isOpen, user }) => {
const { const {
register, register,
formState: { isSubmitting }, formState: { isSubmitting },
@ -73,7 +74,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await estimatesService await estimatesService
.createEstimate(workspaceSlug as string, projectId as string, payload) .createEstimate(workspaceSlug as string, projectId as string, payload, user)
.then(() => { .then(() => {
mutate(ESTIMATES_LIST(projectId as string)); mutate(ESTIMATES_LIST(projectId as string));
onClose(); onClose();
@ -118,7 +119,13 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
); );
await estimatesService await estimatesService
.patchEstimate(workspaceSlug as string, projectId as string, data?.id as string, payload) .patchEstimate(
workspaceSlug as string,
projectId as string,
data?.id as string,
payload,
user
)
.then(() => { .then(() => {
mutate(ESTIMATES_LIST(projectId.toString())); mutate(ESTIMATES_LIST(projectId.toString()));
mutate(ESTIMATE_DETAILS(data.id)); mutate(ESTIMATE_DETAILS(data.id));

View File

@ -16,15 +16,17 @@ import { PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
// helpers // helpers
import { orderArrayBy } from "helpers/array.helper"; import { orderArrayBy } from "helpers/array.helper";
// types // types
import { IEstimate } from "types"; import { ICurrentUserResponse, IEstimate } from "types";
type Props = { type Props = {
user: ICurrentUserResponse | undefined;
estimate: IEstimate; estimate: IEstimate;
editEstimate: (estimate: IEstimate) => void; editEstimate: (estimate: IEstimate) => void;
handleEstimateDelete: (estimateId: string) => void; handleEstimateDelete: (estimateId: string) => void;
}; };
export const SingleEstimate: React.FC<Props> = ({ export const SingleEstimate: React.FC<Props> = ({
user,
estimate, estimate,
editEstimate, editEstimate,
handleEstimateDelete, handleEstimateDelete,
@ -52,7 +54,7 @@ export const SingleEstimate: React.FC<Props> = ({
}, false); }, false);
await projectService await projectService
.updateProject(workspaceSlug as string, projectId as string, payload) .updateProject(workspaceSlug as string, projectId as string, payload, user)
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
type: "error", type: "error",

View File

@ -15,7 +15,7 @@ import { DangerButton, Input, SecondaryButton } from "components/ui";
// icons // icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types // types
import { IImporterService } from "types"; import { ICurrentUserResponse, IImporterService } from "types";
// fetch-keys // fetch-keys
import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys"; import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
data: IImporterService | null; data: IImporterService | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data }) => { export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data, user }) => {
const [deleteLoading, setDeleteLoading] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false);
const [confirmDeleteImport, setConfirmDeleteImport] = useState(false); const [confirmDeleteImport, setConfirmDeleteImport] = useState(false);
@ -45,7 +46,7 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data }
false false
); );
IntegrationService.deleteImporterService(workspaceSlug as string, data.service, data.id) IntegrationService.deleteImporterService(workspaceSlug as string, data.service, data.id, user)
.catch(() => .catch(() =>
setToastAlert({ setToastAlert({
type: "error", type: "error",

View File

@ -27,7 +27,7 @@ import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline";
// images // images
import GithubLogo from "public/services/github.png"; import GithubLogo from "public/services/github.png";
// types // types
import { IGithubRepoCollaborator, IGithubServiceImportFormData } from "types"; import { ICurrentUserResponse, IGithubRepoCollaborator, IGithubServiceImportFormData } from "types";
// fetch-keys // fetch-keys
import { import {
APP_INTEGRATIONS, APP_INTEGRATIONS,
@ -89,7 +89,11 @@ const integrationWorkflowData = [
}, },
]; ];
export const GithubImporterRoot = () => { type Props = {
user: ICurrentUserResponse | undefined;
};
export const GithubImporterRoot: React.FC<Props> = ({ user }) => {
const [currentStep, setCurrentStep] = useState<IIntegrationData>({ const [currentStep, setCurrentStep] = useState<IIntegrationData>({
state: "import-configure", state: "import-configure",
}); });
@ -157,7 +161,7 @@ export const GithubImporterRoot = () => {
project_id: formData.project, project_id: formData.project,
}; };
await GithubIntegrationService.createGithubServiceImport(workspaceSlug as string, payload) await GithubIntegrationService.createGithubServiceImport(workspaceSlug as string, payload, user)
.then(() => { .then(() => {
router.push(`/${workspaceSlug}/settings/import-export`); router.push(`/${workspaceSlug}/settings/import-export`);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)); mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string));

View File

@ -6,6 +6,8 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services // services
import IntegrationService from "services/integration"; import IntegrationService from "services/integration";
// components // components
@ -35,6 +37,8 @@ const IntegrationGuide = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, provider } = router.query; const { workspaceSlug, provider } = router.query;
const { user } = useUserAuth();
const { data: importerServices } = useSWR( const { data: importerServices } = useSWR(
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null, workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null,
workspaceSlug ? () => IntegrationService.getImporterServicesList(workspaceSlug as string) : null workspaceSlug ? () => IntegrationService.getImporterServicesList(workspaceSlug as string) : null
@ -51,6 +55,7 @@ const IntegrationGuide = () => {
isOpen={deleteImportModal} isOpen={deleteImportModal}
handleClose={() => setDeleteImportModal(false)} handleClose={() => setDeleteImportModal(false)}
data={importToDelete} data={importToDelete}
user={user}
/> />
<div className="h-full space-y-2"> <div className="h-full space-y-2">
{!provider && ( {!provider && (
@ -156,8 +161,8 @@ const IntegrationGuide = () => {
</> </>
)} )}
{provider && provider === "github" && <GithubImporterRoot />} {provider && provider === "github" && <GithubImporterRoot user={user} />}
{provider && provider === "jira" && <JiraImporterRoot />} {provider && provider === "jira" && <JiraImporterRoot user={user} />}
</div> </div>
</> </>
); );

View File

@ -35,7 +35,7 @@ import {
import JiraLogo from "public/services/jira.png"; import JiraLogo from "public/services/jira.png";
import { IJiraImporterForm } from "types"; import { ICurrentUserResponse, IJiraImporterForm } from "types";
const integrationWorkflowData: Array<{ const integrationWorkflowData: Array<{
title: string; title: string;
@ -64,7 +64,11 @@ const integrationWorkflowData: Array<{
}, },
]; ];
export const JiraImporterRoot = () => { type Props = {
user: ICurrentUserResponse | undefined;
};
export const JiraImporterRoot: React.FC<Props> = ({ user }) => {
const [currentStep, setCurrentStep] = useState<IJiraIntegrationData>({ const [currentStep, setCurrentStep] = useState<IJiraIntegrationData>({
state: "import-configure", state: "import-configure",
}); });
@ -85,7 +89,7 @@ export const JiraImporterRoot = () => {
if (!workspaceSlug) return; if (!workspaceSlug) return;
await jiraImporterService await jiraImporterService
.createJiraImporter(workspaceSlug.toString(), data) .createJiraImporter(workspaceSlug.toString(), data, user)
.then(() => { .then(() => {
mutate(IMPORTER_SERVICES_LIST(workspaceSlug.toString())); mutate(IMPORTER_SERVICES_LIST(workspaceSlug.toString()));
router.push(`/${workspaceSlug}/settings/import-export`); router.push(`/${workspaceSlug}/settings/import-export`);

View File

@ -27,7 +27,7 @@ import { Loader } from "components/ui";
import { renderShortNumericDateFormat, timeAgo } from "helpers/date-time.helper"; import { renderShortNumericDateFormat, timeAgo } from "helpers/date-time.helper";
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
// types // types
import { IIssueComment, IIssueLabels } from "types"; import { ICurrentUserResponse, IIssueComment, IIssueLabels } from "types";
import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
import useEstimateOption from "hooks/use-estimate-option"; import useEstimateOption from "hooks/use-estimate-option";
@ -110,7 +110,11 @@ const activityDetails: {
}, },
}; };
export const IssueActivitySection: React.FC = () => { type Props = {
user: ICurrentUserResponse | undefined;
};
export const IssueActivitySection: React.FC<Props> = ({ user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
@ -143,7 +147,8 @@ export const IssueActivitySection: React.FC = () => {
projectId as string, projectId as string,
issueId as string, issueId as string,
comment.id, comment.id,
comment comment,
user
) )
.then((res) => { .then((res) => {
mutateIssueActivities(); mutateIssueActivities();
@ -160,7 +165,8 @@ export const IssueActivitySection: React.FC = () => {
workspaceSlug as string, workspaceSlug as string,
projectId as string, projectId as string,
issueId as string, issueId as string,
commentId commentId,
user
) )
.then(() => mutateIssueActivities()); .then(() => mutateIssueActivities());
}; };

View File

@ -14,7 +14,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { Loader, SecondaryButton } from "components/ui"; import { Loader, SecondaryButton } from "components/ui";
// types // types
import type { IIssueComment } from "types"; import type { ICurrentUserResponse, IIssueComment } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
@ -40,7 +40,11 @@ const defaultValues: Partial<IIssueComment> = {
comment_html: "", comment_html: "",
}; };
export const AddComment: React.FC = () => { type Props = {
user: ICurrentUserResponse | undefined;
};
export const AddComment: React.FC<Props> = ({ user }) => {
const { const {
handleSubmit, handleSubmit,
control, control,
@ -67,7 +71,13 @@ export const AddComment: React.FC = () => {
) )
return; return;
await issuesServices await issuesServices
.createIssueComment(workspaceSlug as string, projectId as string, issueId as string, formData) .createIssueComment(
workspaceSlug as string,
projectId as string,
issueId as string,
formData,
user
)
.then(() => { .then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
reset(defaultValues); reset(defaultValues);

View File

@ -17,7 +17,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui // ui
import { SecondaryButton, DangerButton } from "components/ui"; import { SecondaryButton, DangerButton } from "components/ui";
// types // types
import type { IIssue } from "types"; import type { ICurrentUserResponse, IIssue } from "types";
// fetch-keys // fetch-keys
import { import {
CYCLE_ISSUES_WITH_PARAMS, CYCLE_ISSUES_WITH_PARAMS,
@ -30,9 +30,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
data: IIssue | null; data: IIssue | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data }) => { export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter(); const router = useRouter();
@ -57,7 +58,7 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
if (!workspaceSlug || !projectId || !data) return; if (!workspaceSlug || !projectId || !data) return;
await issueServices await issueServices
.deleteIssue(workspaceSlug as string, projectId as string, data.id) .deleteIssue(workspaceSlug as string, projectId as string, data.id, user)
.then(() => { .then(() => {
if (issueView === "calendar") { if (issueView === "calendar") {
const calendarFetchKey = cycleId const calendarFetchKey = cycleId

View File

@ -39,7 +39,7 @@ import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
// helpers // helpers
import { cosineSimilarity } from "helpers/string.helper"; import { cosineSimilarity } from "helpers/string.helper";
// types // types
import type { IIssue } from "types"; import type { ICurrentUserResponse, IIssue } from "types";
// rich-text-editor // rich-text-editor
const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), {
ssr: false, ssr: false,
@ -91,6 +91,7 @@ export interface IssueFormProps {
setCreateMore: React.Dispatch<React.SetStateAction<boolean>>; setCreateMore: React.Dispatch<React.SetStateAction<boolean>>;
handleClose: () => void; handleClose: () => void;
status: boolean; status: boolean;
user: ICurrentUserResponse | undefined;
} }
export const IssueForm: FC<IssueFormProps> = ({ export const IssueForm: FC<IssueFormProps> = ({
@ -103,6 +104,7 @@ export const IssueForm: FC<IssueFormProps> = ({
setCreateMore, setCreateMore,
handleClose, handleClose,
status, status,
user,
}) => { }) => {
// states // states
const [mostSimilarIssue, setMostSimilarIssue] = useState<IIssue | undefined>(); const [mostSimilarIssue, setMostSimilarIssue] = useState<IIssue | undefined>();
@ -177,10 +179,15 @@ export const IssueForm: FC<IssueFormProps> = ({
setIAmFeelingLucky(true); setIAmFeelingLucky(true);
aiService aiService
.createGptTask(workspaceSlug as string, projectId as string, { .createGptTask(
prompt: issueName, workspaceSlug as string,
task: "Generate a proper description for this issue in context of a project management software.", projectId as string,
}) {
prompt: issueName,
task: "Generate a proper description for this issue in context of a project management software.",
},
user
)
.then((res) => { .then((res) => {
if (res.response === "") if (res.response === "")
setToastAlert({ setToastAlert({
@ -227,12 +234,18 @@ export const IssueForm: FC<IssueFormProps> = ({
isOpen={stateModal} isOpen={stateModal}
handleClose={() => setStateModal(false)} handleClose={() => setStateModal(false)}
projectId={projectId} projectId={projectId}
user={user}
/>
<CreateUpdateCycleModal
isOpen={cycleModal}
handleClose={() => setCycleModal(false)}
user={user}
/> />
<CreateUpdateCycleModal isOpen={cycleModal} handleClose={() => setCycleModal(false)} />
<CreateLabelModal <CreateLabelModal
isOpen={labelModal} isOpen={labelModal}
handleClose={() => setLabelModal(false)} handleClose={() => setLabelModal(false)}
projectId={projectId} projectId={projectId}
user={user}
/> />
</> </>
)} )}

View File

@ -102,9 +102,15 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await issuesService await issuesService
.addIssueToCycle(workspaceSlug as string, activeProject ?? "", cycleId, { .addIssueToCycle(
issues: [issueId], workspaceSlug as string,
}) activeProject ?? "",
cycleId,
{
issues: [issueId],
},
user
)
.then(() => { .then(() => {
if (cycleId) { if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params)); mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params));
@ -117,9 +123,15 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await modulesService await modulesService
.addIssuesToModule(workspaceSlug as string, activeProject ?? "", moduleId as string, { .addIssuesToModule(
issues: [issueId], workspaceSlug as string,
}) activeProject ?? "",
moduleId as string,
{
issues: [issueId],
},
user
)
.then(() => { .then(() => {
if (moduleId) { if (moduleId) {
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
@ -148,7 +160,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
if (!workspaceSlug) return; if (!workspaceSlug) return;
await issuesService await issuesService
.createIssues(workspaceSlug as string, activeProject ?? "", payload) .createIssues(workspaceSlug as string, activeProject ?? "", payload, user)
.then(async (res) => { .then(async (res) => {
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle); if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle);
@ -180,7 +192,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
const updateIssue = async (payload: Partial<IIssue>) => { const updateIssue = async (payload: Partial<IIssue>) => {
await issuesService await issuesService
.updateIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload) .updateIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload, user)
.then((res) => { .then((res) => {
if (isUpdatingSingleIssue) { if (isUpdatingSingleIssue) {
mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false); mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false);
@ -261,6 +273,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
projectId={activeProject ?? ""} projectId={activeProject ?? ""}
setActiveProject={setActiveProject} setActiveProject={setActiveProject}
status={data ? true : false} status={data ? true : false}
user={user}
/> />
</Dialog.Panel> </Dialog.Panel>
</Transition.Child> </Transition.Child>

View File

@ -7,6 +7,7 @@ import { mutate } from "swr";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// components // components
@ -37,6 +38,9 @@ type Props = {
export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId }) => { export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const partialUpdateIssue = useCallback( const partialUpdateIssue = useCallback(
@ -55,7 +59,7 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
); );
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId, formData) .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user)
.then((res) => { .then((res) => {
mutate(USER_ISSUE(workspaceSlug as string)); mutate(USER_ISSUE(workspaceSlug as string));
}) })
@ -110,6 +114,7 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
<ViewPrioritySelect <ViewPrioritySelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -117,6 +122,7 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
<ViewStateSelect <ViewStateSelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}
@ -124,6 +130,7 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
<ViewDueDateSelect <ViewDueDateSelect
issue={issue} issue={issue}
partialUpdateIssue={partialUpdateIssue} partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed} isNotAllowed={isNotAllowed}
/> />
)} )}

View File

@ -12,6 +12,7 @@ import { TwitterPicker } from "react-color";
import { Popover, Listbox, Transition } from "@headlessui/react"; import { Popover, Listbox, Transition } from "@headlessui/react";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
import modulesService from "services/modules.service"; import modulesService from "services/modules.service";
@ -76,6 +77,8 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
const { user } = useUserAuth();
const { memberRole } = useProjectMyMembership(); const { memberRole } = useProjectMyMembership();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -110,7 +113,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
const handleNewLabel = (formData: any) => { const handleNewLabel = (formData: any) => {
if (!workspaceSlug || !projectId || isSubmitting) return; if (!workspaceSlug || !projectId || isSubmitting) return;
issuesService issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData) .createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => { .then((res) => {
reset(defaultValues); reset(defaultValues);
issueLabelMutate((prevData) => [...(prevData ?? []), res], false); issueLabelMutate((prevData) => [...(prevData ?? []), res], false);
@ -124,9 +127,15 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
if (!workspaceSlug || !projectId || !issueDetail) return; if (!workspaceSlug || !projectId || !issueDetail) return;
issuesService issuesService
.addIssueToCycle(workspaceSlug as string, projectId as string, cycleDetails.id, { .addIssueToCycle(
issues: [issueDetail.id], workspaceSlug as string,
}) projectId as string,
cycleDetails.id,
{
issues: [issueDetail.id],
},
user
)
.then((res) => { .then((res) => {
mutate(ISSUE_DETAILS(issueId as string)); mutate(ISSUE_DETAILS(issueId as string));
}); });
@ -139,9 +148,15 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
if (!workspaceSlug || !projectId || !issueDetail) return; if (!workspaceSlug || !projectId || !issueDetail) return;
modulesService modulesService
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleDetail.id, { .addIssuesToModule(
issues: [issueDetail.id], workspaceSlug as string,
}) projectId as string,
moduleDetail.id,
{
issues: [issueDetail.id],
},
user
)
.then((res) => { .then((res) => {
mutate(ISSUE_DETAILS(issueId as string)); mutate(ISSUE_DETAILS(issueId as string));
}); });
@ -228,6 +243,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
handleClose={() => setDeleteIssueModal(false)} handleClose={() => setDeleteIssueModal(false)}
isOpen={deleteIssueModal} isOpen={deleteIssueModal}
data={issueDetail ?? null} data={issueDetail ?? null}
user={user}
/> />
<div className="sticky top-5 w-full divide-y-2 divide-brand-base"> <div className="sticky top-5 w-full divide-y-2 divide-brand-base">
<div className="flex items-center justify-between pb-3"> <div className="flex items-center justify-between pb-3">

View File

@ -21,15 +21,16 @@ import { ChevronRightIcon, PlusIcon, XMarkIcon } from "@heroicons/react/24/outli
// helpers // helpers
import { orderArrayBy } from "helpers/array.helper"; import { orderArrayBy } from "helpers/array.helper";
// types // types
import { IIssue, ISubIssueResponse } from "types"; import { ICurrentUserResponse, IIssue, ISubIssueResponse } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys"; import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys";
type Props = { type Props = {
parentIssue: IIssue; parentIssue: IIssue;
user: ICurrentUserResponse | undefined;
}; };
export const SubIssuesList: FC<Props> = ({ parentIssue }) => { export const SubIssuesList: FC<Props> = ({ parentIssue, user }) => {
// states // states
const [createIssueModal, setCreateIssueModal] = useState(false); const [createIssueModal, setCreateIssueModal] = useState(false);
const [subIssuesListModal, setSubIssuesListModal] = useState(false); const [subIssuesListModal, setSubIssuesListModal] = useState(false);
@ -134,7 +135,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue }) => {
); );
issuesService issuesService
.patchIssue(workspaceSlug.toString(), projectId.toString(), issueId, { parent: null }) .patchIssue(workspaceSlug.toString(), projectId.toString(), issueId, { parent: null }, user)
.then((res) => { .then((res) => {
mutate(SUB_ISSUES(parentIssue.id ?? "")); mutate(SUB_ISSUES(parentIssue.id ?? ""));

View File

@ -12,7 +12,7 @@ import { AssigneesList, Avatar, CustomSearchSelect, Tooltip } from "components/u
// icons // icons
import { UserGroupIcon } from "@heroicons/react/24/outline"; import { UserGroupIcon } from "@heroicons/react/24/outline";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch-keys // fetch-keys
import { PROJECT_MEMBERS } from "constants/fetch-keys"; import { PROJECT_MEMBERS } from "constants/fetch-keys";
@ -22,6 +22,7 @@ type Props = {
position?: "left" | "right"; position?: "left" | "right";
selfPositioned?: boolean; selfPositioned?: boolean;
tooltipPosition?: "left" | "right"; tooltipPosition?: "left" | "right";
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -31,6 +32,7 @@ export const ViewAssigneeSelect: React.FC<Props> = ({
position = "left", position = "left",
selfPositioned = false, selfPositioned = false,
tooltipPosition = "right", tooltipPosition = "right",
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -83,7 +85,8 @@ export const ViewAssigneeSelect: React.FC<Props> = ({
projectName: issue.project_detail.name, projectName: issue.project_detail.name,
issueId: issue.id, issueId: issue.id,
}, },
"ISSUE_PROPERTY_UPDATE_ASSIGNEE" "ISSUE_PROPERTY_UPDATE_ASSIGNEE",
user
); );
}} }}
options={options} options={options}

View File

@ -7,15 +7,21 @@ import { findHowManyDaysLeft } from "helpers/date-time.helper";
// services // services
import trackEventServices from "services/track-event.service"; import trackEventServices from "services/track-event.service";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void; partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
export const ViewDueDateSelect: React.FC<Props> = ({ issue, partialUpdateIssue, isNotAllowed }) => { export const ViewDueDateSelect: React.FC<Props> = ({
issue,
partialUpdateIssue,
user,
isNotAllowed,
}) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
@ -51,7 +57,8 @@ export const ViewDueDateSelect: React.FC<Props> = ({ issue, partialUpdateIssue,
projectName: issue.project_detail.name, projectName: issue.project_detail.name,
issueId: issue.id, issueId: issue.id,
}, },
"ISSUE_PROPERTY_UPDATE_DUE_DATE" "ISSUE_PROPERTY_UPDATE_DUE_DATE",
user
); );
}} }}
className={issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} className={issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"}

View File

@ -11,13 +11,14 @@ import { CustomSelect, Tooltip } from "components/ui";
// icons // icons
import { PlayIcon } from "@heroicons/react/24/outline"; import { PlayIcon } from "@heroicons/react/24/outline";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void; partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void;
position?: "left" | "right"; position?: "left" | "right";
selfPositioned?: boolean; selfPositioned?: boolean;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -26,6 +27,7 @@ export const ViewEstimateSelect: React.FC<Props> = ({
partialUpdateIssue, partialUpdateIssue,
position = "left", position = "left",
selfPositioned = false, selfPositioned = false,
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -51,7 +53,8 @@ export const ViewEstimateSelect: React.FC<Props> = ({
projectName: issue.project_detail.name, projectName: issue.project_detail.name,
issueId: issue.id, issueId: issue.id,
}, },
"ISSUE_PROPERTY_UPDATE_ESTIMATE" "ISSUE_PROPERTY_UPDATE_ESTIMATE",
user
); );
}} }}
label={ label={

View File

@ -7,7 +7,7 @@ import { CustomSelect, Tooltip } from "components/ui";
// icons // icons
import { getPriorityIcon } from "components/icons/priority-icon"; import { getPriorityIcon } from "components/icons/priority-icon";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// constants // constants
import { PRIORITIES } from "constants/project"; import { PRIORITIES } from "constants/project";
// services // services
@ -18,6 +18,7 @@ type Props = {
partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void; partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void;
position?: "left" | "right"; position?: "left" | "right";
selfPositioned?: boolean; selfPositioned?: boolean;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -26,6 +27,7 @@ export const ViewPrioritySelect: React.FC<Props> = ({
partialUpdateIssue, partialUpdateIssue,
position = "left", position = "left",
selfPositioned = false, selfPositioned = false,
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -45,7 +47,8 @@ export const ViewPrioritySelect: React.FC<Props> = ({
projectName: issue.project_detail.name, projectName: issue.project_detail.name,
issueId: issue.id, issueId: issue.id,
}, },
"ISSUE_PROPERTY_UPDATE_PRIORITY" "ISSUE_PROPERTY_UPDATE_PRIORITY",
user
); );
}} }}
maxHeight="md" maxHeight="md"

View File

@ -13,7 +13,7 @@ import { getStateGroupIcon } from "components/icons";
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
import { getStatesList } from "helpers/state.helper"; import { getStatesList } from "helpers/state.helper";
// types // types
import { IIssue } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch-keys // fetch-keys
import { STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
@ -22,6 +22,7 @@ type Props = {
partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void; partialUpdateIssue: (formData: Partial<IIssue>, issueId: string) => void;
position?: "left" | "right"; position?: "left" | "right";
selfPositioned?: boolean; selfPositioned?: boolean;
user: ICurrentUserResponse | undefined;
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
@ -30,6 +31,7 @@ export const ViewStateSelect: React.FC<Props> = ({
partialUpdateIssue, partialUpdateIssue,
position = "left", position = "left",
selfPositioned = false, selfPositioned = false,
user,
isNotAllowed, isNotAllowed,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -77,21 +79,25 @@ export const ViewStateSelect: React.FC<Props> = ({
projectName: issue.project_detail.name, projectName: issue.project_detail.name,
issueId: issue.id, issueId: issue.id,
}, },
"ISSUE_PROPERTY_UPDATE_STATE" "ISSUE_PROPERTY_UPDATE_STATE",
user
); );
const oldState = states.find((s) => s.id === issue.state); const oldState = states.find((s) => s.id === issue.state);
const newState = states.find((s) => s.id === data); const newState = states.find((s) => s.id === data);
if (oldState?.group !== "completed" && newState?.group !== "completed") { if (oldState?.group !== "completed" && newState?.group !== "completed") {
trackEventServices.trackIssueMarkedAsDoneEvent({ trackEventServices.trackIssueMarkedAsDoneEvent(
workspaceSlug: issue.workspace_detail.slug, {
workspaceId: issue.workspace_detail.id, workspaceSlug: issue.workspace_detail.slug,
projectId: issue.project_detail.id, workspaceId: issue.workspace_detail.id,
projectIdentifier: issue.project_detail.identifier, projectId: issue.project_detail.id,
projectName: issue.project_detail.name, projectIdentifier: issue.project_detail.identifier,
issueId: issue.id, projectName: issue.project_detail.name,
}); issueId: issue.id,
},
user
);
} }
}} }}
options={options} options={options}

View File

@ -17,7 +17,7 @@ import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// icons // icons
import { ChevronDownIcon } from "@heroicons/react/24/outline"; import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types // types
import type { IIssueLabels, IState } from "types"; import type { ICurrentUserResponse, IIssueLabels, IState } from "types";
// constants // constants
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
@ -26,6 +26,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
projectId: string; projectId: string;
handleClose: () => void; handleClose: () => void;
user: ICurrentUserResponse | undefined;
}; };
const defaultValues: Partial<IState> = { const defaultValues: Partial<IState> = {
@ -33,7 +34,7 @@ const defaultValues: Partial<IState> = {
color: "#858E96", color: "#858E96",
}; };
export const CreateLabelModal: React.FC<Props> = ({ isOpen, projectId, handleClose }) => { export const CreateLabelModal: React.FC<Props> = ({ isOpen, projectId, handleClose, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
@ -57,7 +58,7 @@ export const CreateLabelModal: React.FC<Props> = ({ isOpen, projectId, handleClo
if (!workspaceSlug) return; if (!workspaceSlug) return;
await issuesService await issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData) .createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => { .then((res) => {
mutate<IIssueLabels[]>( mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId), PROJECT_ISSUE_LABELS(projectId),

View File

@ -6,6 +6,8 @@ import { mutate } from "swr";
// react-hook-form // react-hook-form
import { Controller, SubmitHandler, useForm } from "react-hook-form"; import { Controller, SubmitHandler, useForm } from "react-hook-form";
// hooks
import useUserAuth from "hooks/use-user-auth";
// react-color // react-color
import { TwitterPicker } from "react-color"; import { TwitterPicker } from "react-color";
// headless ui // headless ui
@ -42,6 +44,8 @@ export const CreateUpdateLabelInline = forwardRef<Ref, Props>(function CreateUpd
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { const {
handleSubmit, handleSubmit,
control, control,
@ -58,7 +62,7 @@ export const CreateUpdateLabelInline = forwardRef<Ref, Props>(function CreateUpd
if (!workspaceSlug || !projectId || isSubmitting) return; if (!workspaceSlug || !projectId || isSubmitting) return;
await issuesService await issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData) .createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => { .then((res) => {
mutate<IIssueLabels[]>( mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId as string), PROJECT_ISSUE_LABELS(projectId as string),
@ -78,7 +82,8 @@ export const CreateUpdateLabelInline = forwardRef<Ref, Props>(function CreateUpd
workspaceSlug as string, workspaceSlug as string,
projectId as string, projectId as string,
labelToUpdate?.id ?? "", labelToUpdate?.id ?? "",
formData formData,
user
) )
.then(() => { .then(() => {
reset(defaultValues); reset(defaultValues);

View File

@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { DangerButton, SecondaryButton } from "components/ui"; import { DangerButton, SecondaryButton } from "components/ui";
// types // types
import type { IIssueLabels } from "types"; import type { ICurrentUserResponse, IIssueLabels } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
data: IIssueLabels | null; data: IIssueLabels | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteLabelModal: React.FC<Props> = ({ isOpen, onClose, data }) => { export const DeleteLabelModal: React.FC<Props> = ({ isOpen, onClose, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter(); const router = useRouter();
@ -50,7 +51,7 @@ export const DeleteLabelModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
); );
await issuesService await issuesService
.deleteIssueLabel(workspaceSlug.toString(), projectId.toString(), data.id) .deleteIssueLabel(workspaceSlug.toString(), projectId.toString(), data.id, user)
.then(() => handleClose()) .then(() => handleClose())
.catch(() => { .catch(() => {
setIsDeleteLoading(false); setIsDeleteLoading(false);

View File

@ -11,7 +11,7 @@ import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/out
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// types // types
import { IIssueLabels } from "types"; import { ICurrentUserResponse, IIssueLabels } from "types";
// constants // constants
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
@ -19,9 +19,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
parent: IIssueLabels | undefined; parent: IIssueLabels | undefined;
user: ICurrentUserResponse | undefined;
}; };
export const LabelsListModal: React.FC<Props> = ({ isOpen, handleClose, parent }) => { export const LabelsListModal: React.FC<Props> = ({ isOpen, handleClose, parent, user }) => {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const router = useRouter(); const router = useRouter();
@ -58,9 +59,15 @@ export const LabelsListModal: React.FC<Props> = ({ isOpen, handleClose, parent }
); );
await issuesService await issuesService
.patchIssueLabel(workspaceSlug as string, projectId as string, label.id, { .patchIssueLabel(
parent: parent?.id ?? "", workspaceSlug as string,
}) projectId as string,
label.id,
{
parent: parent?.id ?? "",
},
user
)
.then(() => mutate()); .then(() => mutate());
}; };

View File

@ -20,7 +20,7 @@ import {
TrashIcon, TrashIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
// types // types
import { IIssueLabels } from "types"; import { ICurrentUserResponse, IIssueLabels } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
@ -30,6 +30,7 @@ type Props = {
addLabelToGroup: (parentLabel: IIssueLabels) => void; addLabelToGroup: (parentLabel: IIssueLabels) => void;
editLabel: (label: IIssueLabels) => void; editLabel: (label: IIssueLabels) => void;
handleLabelDelete: () => void; handleLabelDelete: () => void;
user: ICurrentUserResponse | undefined;
}; };
export const SingleLabelGroup: React.FC<Props> = ({ export const SingleLabelGroup: React.FC<Props> = ({
@ -38,6 +39,7 @@ export const SingleLabelGroup: React.FC<Props> = ({
addLabelToGroup, addLabelToGroup,
editLabel, editLabel,
handleLabelDelete, handleLabelDelete,
user,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -57,9 +59,15 @@ export const SingleLabelGroup: React.FC<Props> = ({
); );
issuesService issuesService
.patchIssueLabel(workspaceSlug as string, projectId as string, label.id, { .patchIssueLabel(
parent: null, workspaceSlug as string,
}) projectId as string,
label.id,
{
parent: null,
},
user
)
.then(() => { .then(() => {
mutate(PROJECT_ISSUE_LABELS(projectId as string)); mutate(PROJECT_ISSUE_LABELS(projectId as string));
}); });

View File

@ -15,7 +15,7 @@ import { SecondaryButton, DangerButton } from "components/ui";
// icons // icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types // types
import type { IModule } from "types"; import type { ICurrentUserResponse, IModule } from "types";
// fetch-keys // fetch-keys
import { MODULE_LIST } from "constants/fetch-keys"; import { MODULE_LIST } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data?: IModule; data?: IModule;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data }) => { export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter(); const router = useRouter();
@ -50,7 +51,7 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
); );
await modulesService await modulesService
.deleteModule(workspaceSlug as string, projectId as string, data.id) .deleteModule(workspaceSlug as string, projectId as string, data.id, user)
.then(() => { .then(() => {
if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`); if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
handleClose(); handleClose();

View File

@ -15,7 +15,7 @@ import modulesService from "services/modules.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// types // types
import type { IModule } from "types"; import type { ICurrentUserResponse, IModule } from "types";
// fetch-keys // fetch-keys
import { MODULE_LIST } from "constants/fetch-keys"; import { MODULE_LIST } from "constants/fetch-keys";
@ -23,6 +23,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data?: IModule; data?: IModule;
user: ICurrentUserResponse | undefined;
}; };
const defaultValues: Partial<IModule> = { const defaultValues: Partial<IModule> = {
@ -33,7 +34,7 @@ const defaultValues: Partial<IModule> = {
members_list: [], members_list: [],
}; };
export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data }) => { export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -50,7 +51,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
const createModule = async (payload: Partial<IModule>) => { const createModule = async (payload: Partial<IModule>) => {
await modulesService await modulesService
.createModule(workspaceSlug as string, projectId as string, payload) .createModule(workspaceSlug as string, projectId as string, payload, user)
.then(() => { .then(() => {
mutate(MODULE_LIST(projectId as string)); mutate(MODULE_LIST(projectId as string));
handleClose(); handleClose();
@ -72,7 +73,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
const updateModule = async (payload: Partial<IModule>) => { const updateModule = async (payload: Partial<IModule>) => {
await modulesService await modulesService
.updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload) .updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload, user)
.then((res) => { .then((res) => {
mutate<IModule[]>( mutate<IModule[]>(
MODULE_LIST(projectId as string), MODULE_LIST(projectId as string),

View File

@ -37,7 +37,7 @@ import { LinkIcon } from "@heroicons/react/20/solid";
import { renderDateFormat, renderShortDate } from "helpers/date-time.helper"; import { renderDateFormat, renderShortDate } from "helpers/date-time.helper";
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
// types // types
import { IIssue, IModule, ModuleLink } from "types"; import { ICurrentUserResponse, IIssue, IModule, ModuleLink } from "types";
// fetch-keys // fetch-keys
import { MODULE_DETAILS } from "constants/fetch-keys"; import { MODULE_DETAILS } from "constants/fetch-keys";
// constant // constant
@ -56,9 +56,16 @@ type Props = {
module?: IModule; module?: IModule;
isOpen: boolean; isOpen: boolean;
moduleIssues?: IIssue[]; moduleIssues?: IIssue[];
user: ICurrentUserResponse | undefined;
}; };
export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen, moduleIssues }) => { export const ModuleDetailsSidebar: React.FC<Props> = ({
issues,
module,
isOpen,
moduleIssues,
user,
}) => {
const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
const [moduleLinkModal, setModuleLinkModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false);
@ -86,7 +93,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
); );
modulesService modulesService
.patchModule(workspaceSlug as string, projectId as string, moduleId as string, data) .patchModule(workspaceSlug as string, projectId as string, moduleId as string, data, user)
.then(() => mutate(MODULE_DETAILS(moduleId as string))) .then(() => mutate(MODULE_DETAILS(moduleId as string)))
.catch((e) => console.log(e)); .catch((e) => console.log(e));
}; };
@ -181,6 +188,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
isOpen={moduleDeleteModal} isOpen={moduleDeleteModal}
setIsOpen={setModuleDeleteModal} setIsOpen={setModuleDeleteModal}
data={module} data={module}
user={user}
/> />
<div <div
className={`fixed top-[66px] ${ className={`fixed top-[66px] ${

View File

@ -27,16 +27,17 @@ import { CalendarMonthIcon, TargetIcon } from "components/icons";
import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper";
import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
// types // types
import { IModule } from "types"; import { ICurrentUserResponse, IModule } from "types";
// fetch-key // fetch-key
import { MODULE_LIST } from "constants/fetch-keys"; import { MODULE_LIST } from "constants/fetch-keys";
type Props = { type Props = {
module: IModule; module: IModule;
handleEditModule: () => void; handleEditModule: () => void;
user: ICurrentUserResponse | undefined;
}; };
export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule }) => { export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule, user }) => {
const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
const router = useRouter(); const router = useRouter();
@ -128,6 +129,7 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
isOpen={moduleDeleteModal} isOpen={moduleDeleteModal}
setIsOpen={setModuleDeleteModal} setIsOpen={setModuleDeleteModal}
data={module} data={module}
user={user}
/> />
<div className="flex flex-col divide-y divide-brand-base overflow-hidden rounded-[10px] border border-brand-base bg-brand-base text-xs"> <div className="flex flex-col divide-y divide-brand-base overflow-hidden rounded-[10px] border border-brand-base bg-brand-base text-xs">
<div className="p-4"> <div className="p-4">

View File

@ -2,16 +2,17 @@
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import workspaceService from "services/workspace.service"; import workspaceService from "services/workspace.service";
import { IUser } from "types"; import { ICurrentUserResponse, IUser } from "types";
// ui components // ui components
import { MultiInput, PrimaryButton, SecondaryButton } from "components/ui"; import { MultiInput, PrimaryButton, SecondaryButton } from "components/ui";
type Props = { type Props = {
setStep: React.Dispatch<React.SetStateAction<number>>; setStep: React.Dispatch<React.SetStateAction<number>>;
workspace: any; workspace: any;
user: ICurrentUserResponse | undefined;
}; };
export const InviteMembers: React.FC<Props> = ({ setStep, workspace }) => { export const InviteMembers: React.FC<Props> = ({ setStep, workspace, user }) => {
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { const {
@ -23,7 +24,7 @@ export const InviteMembers: React.FC<Props> = ({ setStep, workspace }) => {
const onSubmit = async (formData: IUser) => { const onSubmit = async (formData: IUser) => {
await workspaceService await workspaceService
.inviteWorkspace(workspace.slug, formData) .inviteWorkspace(workspace.slug, formData, user)
.then(() => { .then(() => {
setToastAlert({ setToastAlert({
type: "success", type: "success",

View File

@ -9,7 +9,7 @@ import { Tab } from "@headlessui/react";
// services // services
import workspaceService from "services/workspace.service"; import workspaceService from "services/workspace.service";
// types // types
import { IWorkspaceMemberInvitation } from "types"; import { ICurrentUserResponse, IWorkspaceMemberInvitation } from "types";
// fetch-keys // fetch-keys
import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys";
// constants // constants
@ -21,9 +21,10 @@ import { getFirstCharacters, truncateText } from "helpers/string.helper";
type Props = { type Props = {
setStep: React.Dispatch<React.SetStateAction<number>>; setStep: React.Dispatch<React.SetStateAction<number>>;
setWorkspace: React.Dispatch<React.SetStateAction<any>>; setWorkspace: React.Dispatch<React.SetStateAction<any>>;
user: ICurrentUserResponse | undefined;
}; };
export const Workspace: React.FC<Props> = ({ setStep, setWorkspace }) => { export const Workspace: React.FC<Props> = ({ setStep, setWorkspace, user }) => {
const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false);
const [invitationsRespond, setInvitationsRespond] = useState<string[]>([]); const [invitationsRespond, setInvitationsRespond] = useState<string[]>([]);
const [defaultValues, setDefaultValues] = useState({ const [defaultValues, setDefaultValues] = useState({
@ -98,7 +99,7 @@ export const Workspace: React.FC<Props> = ({ setStep, setWorkspace }) => {
> >
<Tab.List as="div" className="flex flex-col gap-3 px-7 pt-7 pb-3.5"> <Tab.List as="div" className="flex flex-col gap-3 px-7 pt-7 pb-3.5">
<div className="flex flex-col gap-2 justify-center"> <div className="flex flex-col gap-2 justify-center">
<h3 className="text-base font-semibold text-brand-base">Workspaces</h3> <h3 className="text-base font-semibold text-brand-base">Workspace</h3>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-brand-secondary">
Create or join the workspace to get started with Plane. Create or join the workspace to get started with Plane.
</p> </p>
@ -161,7 +162,10 @@ export const Workspace: React.FC<Props> = ({ setStep, setWorkspace }) => {
{truncateText(invitation.workspace.name, 30)} {truncateText(invitation.workspace.name, 30)}
</div> </div>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-brand-secondary">
Invited by {invitation.workspace.owner.first_name} Invited by{" "}
{invitation.created_by_detail
? invitation.created_by_detail.first_name
: invitation.workspace.owner.first_name}
</p> </p>
</div> </div>
<div className="flex-shrink-0 self-center"> <div className="flex-shrink-0 self-center">
@ -237,6 +241,7 @@ export const Workspace: React.FC<Props> = ({ setStep, setWorkspace }) => {
}} }}
defaultValues={defaultValues} defaultValues={defaultValues}
setDefaultValues={setDefaultValues} setDefaultValues={setDefaultValues}
user={user}
/> />
</Tab.Panel> </Tab.Panel>
</Tab.Panels> </Tab.Panels>

View File

@ -16,7 +16,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { TextArea } from "components/ui"; import { TextArea } from "components/ui";
// types // types
import { IPageBlock } from "types"; import { ICurrentUserResponse, IPageBlock } from "types";
// fetch-keys // fetch-keys
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
@ -24,7 +24,11 @@ const defaultValues = {
name: "", name: "",
}; };
export const CreateBlock = () => { type Props = {
user: ICurrentUserResponse | undefined;
};
export const CreateBlock: React.FC<Props> = ({ user }) => {
const [blockTitle, setBlockTitle] = useState(""); const [blockTitle, setBlockTitle] = useState("");
const router = useRouter(); const router = useRouter();
@ -49,9 +53,15 @@ export const CreateBlock = () => {
if (!workspaceSlug || !projectId || !pageId) return; if (!workspaceSlug || !projectId || !pageId) return;
await pagesService await pagesService
.createPageBlock(workspaceSlug as string, projectId as string, pageId as string, { .createPageBlock(
name: watch("name"), workspaceSlug as string,
}) projectId as string,
pageId as string,
{
name: watch("name"),
},
user
)
.then((res) => { .then((res) => {
mutate<IPageBlock[]>( mutate<IPageBlock[]>(
PAGE_BLOCKS_LIST(pageId as string), PAGE_BLOCKS_LIST(pageId as string),

View File

@ -20,7 +20,7 @@ import { GptAssistantModal } from "components/core";
// ui // ui
import { Loader, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; import { Loader, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// types // types
import { IPageBlock } from "types"; import { ICurrentUserResponse, IPageBlock } from "types";
// fetch-keys // fetch-keys
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
@ -30,6 +30,7 @@ type Props = {
handleAiAssistance?: (response: string) => void; handleAiAssistance?: (response: string) => void;
setIsSyncing?: React.Dispatch<React.SetStateAction<boolean>>; setIsSyncing?: React.Dispatch<React.SetStateAction<boolean>>;
focus?: keyof IPageBlock; focus?: keyof IPageBlock;
user: ICurrentUserResponse | undefined;
}; };
const defaultValues = { const defaultValues = {
@ -61,6 +62,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
handleAiAssistance, handleAiAssistance,
setIsSyncing, setIsSyncing,
focus, focus,
user,
}) => { }) => {
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
const [gptAssistantModal, setGptAssistantModal] = useState(false); const [gptAssistantModal, setGptAssistantModal] = useState(false);
@ -96,11 +98,17 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
if (!workspaceSlug || !projectId || !pageId) return; if (!workspaceSlug || !projectId || !pageId) return;
await pagesService await pagesService
.createPageBlock(workspaceSlug as string, projectId as string, pageId as string, { .createPageBlock(
name: formData.name, workspaceSlug as string,
description: formData.description ?? "", projectId as string,
description_html: formData.description_html ?? "<p></p>", pageId as string,
}) {
name: formData.name,
description: formData.description ?? "",
description_html: formData.description_html ?? "<p></p>",
},
user
)
.then((res) => { .then((res) => {
mutate<IPageBlock[]>( mutate<IPageBlock[]>(
PAGE_BLOCKS_LIST(pageId as string), PAGE_BLOCKS_LIST(pageId as string),
@ -139,21 +147,34 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
); );
await pagesService await pagesService
.patchPageBlock(workspaceSlug as string, projectId as string, pageId as string, data.id, { .patchPageBlock(
name: formData.name, workspaceSlug as string,
description: formData.description, projectId as string,
description_html: formData.description_html, pageId as string,
}) data.id,
{
name: formData.name,
description: formData.description,
description_html: formData.description_html,
},
user
)
.then((res) => { .then((res) => {
mutate(PAGE_BLOCKS_LIST(pageId as string)); mutate(PAGE_BLOCKS_LIST(pageId as string));
editorRef.current?.setEditorValue(res.description_html); editorRef.current?.setEditorValue(res.description_html);
if (data.issue && data.sync) if (data.issue && data.sync)
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, data.issue, { .patchIssue(
name: res.name, workspaceSlug as string,
description: res.description, projectId as string,
description_html: res.description_html, data.issue,
}) {
name: res.name,
description: res.description,
description_html: res.description_html,
},
user
)
.finally(() => { .finally(() => {
if (setIsSyncing) setIsSyncing(false); if (setIsSyncing) setIsSyncing(false);
}); });
@ -169,10 +190,15 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
setIAmFeelingLucky(true); setIAmFeelingLucky(true);
aiService aiService
.createGptTask(workspaceSlug as string, projectId as string, { .createGptTask(
prompt: watch("name"), workspaceSlug as string,
task: "Generate a proper description for this issue in context of a project management software.", projectId as string,
}) {
prompt: watch("name"),
task: "Generate a proper description for this issue in context of a project management software.",
},
user
)
.then((res) => { .then((res) => {
if (res.response === "") if (res.response === "")
setToastAlert({ setToastAlert({

View File

@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
// components // components
import { PageForm } from "./page-form"; import { PageForm } from "./page-form";
// types // types
import { IPage } from "types"; import { ICurrentUserResponse, IPage } from "types";
// fetch-keys // fetch-keys
import { import {
ALL_PAGES_LIST, ALL_PAGES_LIST,
@ -26,9 +26,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
data?: IPage | null; data?: IPage | null;
user: ICurrentUserResponse | undefined;
}; };
export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, data }) => { export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, data, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -40,7 +41,7 @@ export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, da
const createPage = async (payload: IPage) => { const createPage = async (payload: IPage) => {
await pagesService await pagesService
.createPage(workspaceSlug as string, projectId as string, payload) .createPage(workspaceSlug as string, projectId as string, payload, user)
.then((res) => { .then((res) => {
mutate(RECENT_PAGES_LIST(projectId as string)); mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>( mutate<IPage[]>(
@ -82,7 +83,7 @@ export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, da
const updatePage = async (payload: IPage) => { const updatePage = async (payload: IPage) => {
await pagesService await pagesService
.patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload) .patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload, user)
.then((res) => { .then((res) => {
mutate(RECENT_PAGES_LIST(projectId as string)); mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>( mutate<IPage[]>(

View File

@ -15,7 +15,7 @@ import { DangerButton, SecondaryButton } from "components/ui";
// icons // icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types // types
import type { IPage } from "types"; import type { ICurrentUserResponse, IPage } from "types";
// fetch-keys // fetch-keys
import { import {
ALL_PAGES_LIST, ALL_PAGES_LIST,
@ -28,12 +28,14 @@ type TConfirmPageDeletionProps = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data?: IPage | null; data?: IPage | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({ export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({
isOpen, isOpen,
setIsOpen, setIsOpen,
data, data,
user,
}) => { }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
@ -52,7 +54,7 @@ export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({
if (!data || !workspaceSlug || !projectId) return; if (!data || !workspaceSlug || !projectId) return;
await pagesService await pagesService
.deletePage(workspaceSlug as string, data.project, data.id) .deletePage(workspaceSlug as string, data.project, data.id, user)
.then(() => { .then(() => {
mutate(RECENT_PAGES_LIST(projectId as string)); mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>( mutate<IPage[]>(

View File

@ -8,6 +8,7 @@ import pagesService from "services/pages.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { import {
CreateUpdatePageModal, CreateUpdatePageModal,
@ -44,6 +45,8 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: people } = useSWR( const { data: people } = useSWR(
@ -181,7 +184,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
); );
pagesService pagesService
.patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData) .patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user)
.then(() => { .then(() => {
mutate(RECENT_PAGES_LIST(projectId.toString())); mutate(RECENT_PAGES_LIST(projectId.toString()));
}); });
@ -193,11 +196,13 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
isOpen={createUpdatePageModal} isOpen={createUpdatePageModal}
handleClose={() => setCreateUpdatePageModal(false)} handleClose={() => setCreateUpdatePageModal(false)}
data={selectedPageToUpdate} data={selectedPageToUpdate}
user={user}
/> />
<DeletePageModal <DeletePageModal
isOpen={deletePageModal} isOpen={deletePageModal}
setIsOpen={setDeletePageModal} setIsOpen={setDeletePageModal}
data={selectedPageToDelete} data={selectedPageToDelete}
user={user}
/> />
{pages ? ( {pages ? (
<div className="space-y-4 h-full overflow-y-auto"> <div className="space-y-4 h-full overflow-y-auto">

View File

@ -35,7 +35,7 @@ import {
// helpers // helpers
import { copyTextToClipboard } from "helpers/string.helper"; import { copyTextToClipboard } from "helpers/string.helper";
// types // types
import { IIssue, IPageBlock, IProject } from "types"; import { ICurrentUserResponse, IIssue, IPageBlock, IProject } from "types";
// fetch-keys // fetch-keys
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
@ -43,9 +43,10 @@ type Props = {
block: IPageBlock; block: IPageBlock;
projectDetails: IProject | undefined; projectDetails: IProject | undefined;
index: number; index: number;
user: ICurrentUserResponse | undefined;
}; };
export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index }) => { export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index, user }) => {
const [isSyncing, setIsSyncing] = useState(false); const [isSyncing, setIsSyncing] = useState(false);
const [createBlockForm, setCreateBlockForm] = useState(false); const [createBlockForm, setCreateBlockForm] = useState(false);
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
@ -87,20 +88,33 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
); );
await pagesService await pagesService
.patchPageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id, { .patchPageBlock(
name: formData.name, workspaceSlug as string,
description: formData.description, projectId as string,
description_html: formData.description_html, pageId as string,
}) block.id,
{
name: formData.name,
description: formData.description,
description_html: formData.description_html,
},
user
)
.then((res) => { .then((res) => {
mutate(PAGE_BLOCKS_LIST(pageId as string)); mutate(PAGE_BLOCKS_LIST(pageId as string));
if (block.issue && block.sync) if (block.issue && block.sync)
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, block.issue, { .patchIssue(
name: res.name, workspaceSlug as string,
description: res.description, projectId as string,
description_html: res.description_html, block.issue,
}) {
name: res.name,
description: res.description,
description_html: res.description_html,
},
user
)
.finally(() => setIsSyncing(false)); .finally(() => setIsSyncing(false));
}); });
}; };
@ -113,7 +127,8 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
workspaceSlug as string, workspaceSlug as string,
projectId as string, projectId as string,
pageId as string, pageId as string,
block.id block.id,
user
) )
.then((res: IIssue) => { .then((res: IIssue) => {
mutate<IPageBlock[]>( mutate<IPageBlock[]>(
@ -152,7 +167,13 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
); );
await pagesService await pagesService
.deletePageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id) .deletePageBlock(
workspaceSlug as string,
projectId as string,
pageId as string,
block.id,
user
)
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
@ -168,10 +189,15 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
setIAmFeelingLucky(true); setIAmFeelingLucky(true);
aiService aiService
.createGptTask(workspaceSlug as string, projectId as string, { .createGptTask(
prompt: block.name, workspaceSlug as string,
task: "Generate a proper description for this issue in context of a project management software.", projectId as string,
}) {
prompt: block.name,
task: "Generate a proper description for this issue in context of a project management software.",
},
user
)
.then((res) => { .then((res) => {
if (res.response === "") if (res.response === "")
setToastAlert({ setToastAlert({
@ -243,7 +269,8 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
block.id, block.id,
{ {
sync: !block.sync, sync: !block.sync,
} },
user
); );
}; };
@ -281,6 +308,7 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
data={block} data={block}
setIsSyncing={setIsSyncing} setIsSyncing={setIsSyncing}
focus="name" focus="name"
user={user}
/> />
</div> </div>
) : ( ) : (

View File

@ -24,7 +24,7 @@ import EmojiIconPicker from "components/emoji-icon-picker";
// helpers // helpers
import { getRandomEmoji } from "helpers/common.helper"; import { getRandomEmoji } from "helpers/common.helper";
// types // types
import { IProject } from "types"; import { ICurrentUserResponse, IProject } from "types";
// fetch-keys // fetch-keys
import { PROJECTS_LIST, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; import { PROJECTS_LIST, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
// constants // constants
@ -33,6 +33,7 @@ import { NETWORK_CHOICES } from "constants/project";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
user: ICurrentUserResponse | undefined;
}; };
const defaultValues: Partial<IProject> = { const defaultValues: Partial<IProject> = {
@ -63,7 +64,7 @@ const IsGuestCondition: React.FC<{
}; };
export const CreateProjectModal: React.FC<Props> = (props) => { export const CreateProjectModal: React.FC<Props> = (props) => {
const { isOpen, setIsOpen } = props; const { isOpen, setIsOpen, user } = props;
const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true); const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true);
@ -120,7 +121,7 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
else payload.emoji = formData.emoji_and_icon; else payload.emoji = formData.emoji_and_icon;
await projectServices await projectServices
.createProject(workspaceSlug as string, payload) .createProject(workspaceSlug as string, payload, user)
.then((res) => { .then((res) => {
mutate<IProject[]>( mutate<IProject[]>(
PROJECTS_LIST(workspaceSlug as string), PROJECTS_LIST(workspaceSlug as string),

View File

@ -13,7 +13,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui // ui
import { DangerButton, Input, SecondaryButton } from "components/ui"; import { DangerButton, Input, SecondaryButton } from "components/ui";
// types // types
import type { IProject, IWorkspace } from "types"; import type { ICurrentUserResponse, IProject, IWorkspace } from "types";
// fetch-keys // fetch-keys
import { PROJECTS_LIST } from "constants/fetch-keys"; import { PROJECTS_LIST } from "constants/fetch-keys";
@ -22,6 +22,7 @@ type TConfirmProjectDeletionProps = {
onClose: () => void; onClose: () => void;
onSuccess?: () => void; onSuccess?: () => void;
data: IProject | null; data: IProject | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = ({ export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = ({
@ -29,6 +30,7 @@ export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = ({
data, data,
onClose, onClose,
onSuccess, onSuccess,
user,
}) => { }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [confirmProjectName, setConfirmProjectName] = useState(""); const [confirmProjectName, setConfirmProjectName] = useState("");
@ -65,7 +67,7 @@ export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = ({
setIsDeleteLoading(true); setIsDeleteLoading(true);
if (!data || !workspaceSlug || !canDelete) return; if (!data || !workspaceSlug || !canDelete) return;
await projectService await projectService
.deleteProject(workspaceSlug, data.id) .deleteProject(workspaceSlug, data.id, user)
.then(() => { .then(() => {
handleClose(); handleClose();
mutate<IProject[]>(PROJECTS_LIST(workspaceSlug), (prevData) => mutate<IProject[]>(PROJECTS_LIST(workspaceSlug), (prevData) =>

View File

@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
import projectService from "services/project.service"; import projectService from "services/project.service";
import workspaceService from "services/workspace.service"; import workspaceService from "services/workspace.service";
// types // types
import { IProjectMemberInvitation } from "types"; import { ICurrentUserResponse, IProjectMemberInvitation } from "types";
// fetch-keys // fetch-keys
import { PROJECT_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys"; import { PROJECT_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys";
// constants // constants
@ -25,6 +25,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
members: any[]; members: any[];
user: ICurrentUserResponse | undefined;
}; };
type ProjectMember = IProjectMemberInvitation & { type ProjectMember = IProjectMemberInvitation & {
@ -40,7 +41,7 @@ const defaultValues: Partial<ProjectMember> = {
user_id: "", user_id: "",
}; };
const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, members }) => { const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, members, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -70,7 +71,7 @@ const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, member
const onSubmit = async (formData: ProjectMember) => { const onSubmit = async (formData: ProjectMember) => {
if (!workspaceSlug || !projectId || isSubmitting) return; if (!workspaceSlug || !projectId || isSubmitting) return;
await projectService await projectService
.inviteProject(workspaceSlug as string, projectId as string, formData) .inviteProject(workspaceSlug as string, projectId as string, formData, user)
.then((response) => { .then((response) => {
setIsOpen(false); setIsOpen(false);
mutate<any[]>( mutate<any[]>(

View File

@ -9,6 +9,7 @@ import { PlusIcon } from "@heroicons/react/24/outline";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useTheme from "hooks/use-theme"; import useTheme from "hooks/use-theme";
import useUserAuth from "hooks/use-user-auth";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
// components // components
@ -29,6 +30,9 @@ export const ProjectSidebarList: FC = () => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
// states // states
const [isCreateProjectModal, setCreateProjectModal] = useState(false); const [isCreateProjectModal, setCreateProjectModal] = useState(false);
// theme // theme
@ -136,11 +140,16 @@ export const ProjectSidebarList: FC = () => {
return ( return (
<> <>
<CreateProjectModal isOpen={isCreateProjectModal} setIsOpen={setCreateProjectModal} /> <CreateProjectModal
isOpen={isCreateProjectModal}
setIsOpen={setCreateProjectModal}
user={user}
/>
<DeleteProjectModal <DeleteProjectModal
isOpen={deleteProjectModal} isOpen={deleteProjectModal}
onClose={() => setDeleteProjectModal(false)} onClose={() => setDeleteProjectModal(false)}
data={projectToDelete} data={projectToDelete}
user={user}
/> />
<div className="mt-2.5 h-full overflow-y-auto border-t border-brand-base bg-brand-sidebar pt-2.5"> <div className="mt-2.5 h-full overflow-y-auto border-t border-brand-base bg-brand-sidebar pt-2.5">
{favoriteProjects && favoriteProjects.length > 0 && ( {favoriteProjects && favoriteProjects.length > 0 && (

View File

@ -19,7 +19,7 @@ import { CustomSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "c
// icons // icons
import { ChevronDownIcon } from "@heroicons/react/24/outline"; import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types // types
import type { IState, IStateResponse } from "types"; import type { ICurrentUserResponse, IState, IStateResponse } from "types";
// fetch keys // fetch keys
import { STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
// constants // constants
@ -30,6 +30,7 @@ type Props = {
isOpen: boolean; isOpen: boolean;
projectId: string; projectId: string;
handleClose: () => void; handleClose: () => void;
user: ICurrentUserResponse | undefined;
}; };
const defaultValues: Partial<IState> = { const defaultValues: Partial<IState> = {
@ -39,7 +40,7 @@ const defaultValues: Partial<IState> = {
group: "backlog", group: "backlog",
}; };
export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClose }) => { export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClose, user }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
@ -69,7 +70,7 @@ export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClo
}; };
await stateService await stateService
.createState(workspaceSlug as string, projectId, payload) .createState(workspaceSlug as string, projectId, payload, user)
.then((res) => { .then((res) => {
mutate<IStateResponse>( mutate<IStateResponse>(
STATES_LIST(projectId.toString()), STATES_LIST(projectId.toString()),

View File

@ -17,7 +17,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui"; import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
// types // types
import type { IState, IStateResponse } from "types"; import type { ICurrentUserResponse, IState, IStateResponse } from "types";
// fetch-keys // fetch-keys
import { STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
// constants // constants
@ -27,6 +27,7 @@ type Props = {
data: IState | null; data: IState | null;
onClose: () => void; onClose: () => void;
selectedGroup: StateGroup | null; selectedGroup: StateGroup | null;
user: ICurrentUserResponse | undefined;
}; };
export type StateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled" | null; export type StateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled" | null;
@ -37,7 +38,12 @@ const defaultValues: Partial<IState> = {
group: "backlog", group: "backlog",
}; };
export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, selectedGroup }) => { export const CreateUpdateStateInline: React.FC<Props> = ({
data,
onClose,
selectedGroup,
user,
}) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -83,7 +89,7 @@ export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, select
if (!data) { if (!data) {
await stateService await stateService
.createState(workspaceSlug.toString(), projectId.toString(), { ...payload }) .createState(workspaceSlug.toString(), projectId.toString(), { ...payload }, user)
.then((res) => { .then((res) => {
mutate<IStateResponse>( mutate<IStateResponse>(
STATES_LIST(projectId.toString()), STATES_LIST(projectId.toString()),
@ -121,9 +127,15 @@ export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, select
}); });
} else { } else {
await stateService await stateService
.updateState(workspaceSlug.toString(), projectId.toString(), data.id, { .updateState(
...payload, workspaceSlug.toString(),
}) projectId.toString(),
data.id,
{
...payload,
},
user
)
.then(() => { .then(() => {
mutate(STATES_LIST(projectId.toString())); mutate(STATES_LIST(projectId.toString()));
handleClose(); handleClose();

View File

@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { DangerButton, SecondaryButton } from "components/ui"; import { DangerButton, SecondaryButton } from "components/ui";
// types // types
import type { IState, IStateResponse } from "types"; import type { ICurrentUserResponse, IState, IStateResponse } from "types";
// fetch-keys // fetch-keys
import { STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
data: IState | null; data: IState | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) => { export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter(); const router = useRouter();
@ -44,7 +45,7 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
setIsDeleteLoading(true); setIsDeleteLoading(true);
await stateServices await stateServices
.deleteState(workspaceSlug as string, data.project, data.id) .deleteState(workspaceSlug as string, data.project, data.id, user)
.then(() => { .then(() => {
mutate<IStateResponse>( mutate<IStateResponse>(
STATES_LIST(data.project), STATES_LIST(data.project),

View File

@ -21,7 +21,7 @@ import { addSpaceIfCamelCase } from "helpers/string.helper";
import { groupBy, orderArrayBy } from "helpers/array.helper"; import { groupBy, orderArrayBy } from "helpers/array.helper";
import { orderStateGroups } from "helpers/state.helper"; import { orderStateGroups } from "helpers/state.helper";
// types // types
import { IState } from "types"; import { ICurrentUserResponse, IState } from "types";
// fetch-keys // fetch-keys
import { STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
@ -31,6 +31,7 @@ type Props = {
statesList: IState[]; statesList: IState[];
handleEditState: () => void; handleEditState: () => void;
handleDeleteState: () => void; handleDeleteState: () => void;
user: ICurrentUserResponse | undefined;
}; };
export const SingleState: React.FC<Props> = ({ export const SingleState: React.FC<Props> = ({
@ -39,6 +40,7 @@ export const SingleState: React.FC<Props> = ({
statesList, statesList,
handleEditState, handleEditState,
handleDeleteState, handleDeleteState,
user,
}) => { }) => {
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
@ -67,14 +69,26 @@ export const SingleState: React.FC<Props> = ({
if (currentDefaultState) if (currentDefaultState)
stateService stateService
.patchState(workspaceSlug as string, projectId as string, currentDefaultState?.id ?? "", { .patchState(
default: false, workspaceSlug as string,
}) projectId as string,
currentDefaultState?.id ?? "",
{
default: false,
},
user
)
.then(() => { .then(() => {
stateService stateService
.patchState(workspaceSlug as string, projectId as string, state.id, { .patchState(
default: true, workspaceSlug as string,
}) projectId as string,
state.id,
{
default: true,
},
user
)
.then(() => { .then(() => {
mutate(STATES_LIST(projectId as string)); mutate(STATES_LIST(projectId as string));
setIsSubmitting(false); setIsSubmitting(false);
@ -85,9 +99,15 @@ export const SingleState: React.FC<Props> = ({
}); });
else else
stateService stateService
.patchState(workspaceSlug as string, projectId as string, state.id, { .patchState(
default: true, workspaceSlug as string,
}) projectId as string,
state.id,
{
default: true,
},
user
)
.then(() => { .then(() => {
mutate(STATES_LIST(projectId as string)); mutate(STATES_LIST(projectId as string));
setIsSubmitting(false); setIsSubmitting(false);
@ -121,9 +141,15 @@ export const SingleState: React.FC<Props> = ({
); );
stateService stateService
.patchState(workspaceSlug as string, projectId as string, state.id, { .patchState(
sequence: newSequence, workspaceSlug as string,
}) projectId as string,
state.id,
{
sequence: newSequence,
},
user
)
.then((res) => { .then((res) => {
console.log(res); console.log(res);
mutate(STATES_LIST(projectId as string)); mutate(STATES_LIST(projectId as string));

View File

@ -15,7 +15,7 @@ import { DangerButton, SecondaryButton } from "components/ui";
// icons // icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types // types
import type { IView } from "types"; import type { ICurrentUserResponse, IView } from "types";
// fetch-keys // fetch-keys
import { VIEWS_LIST } from "constants/fetch-keys"; import { VIEWS_LIST } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data: IView | null; data: IView | null;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, setIsOpen }) => { export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, setIsOpen, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter(); const router = useRouter();
@ -43,7 +44,7 @@ export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, setIsOpen }) =>
if (!workspaceSlug || !data || !projectId) return; if (!workspaceSlug || !data || !projectId) return;
await viewsService await viewsService
.deleteView(workspaceSlug as string, projectId as string, data.id) .deleteView(workspaceSlug as string, projectId as string, data.id, user)
.then(() => { .then(() => {
mutate<IView[]>(VIEWS_LIST(projectId as string), (views) => mutate<IView[]>(VIEWS_LIST(projectId as string), (views) =>
views?.filter((view) => view.id !== data.id) views?.filter((view) => view.id !== data.id)

View File

@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
// components // components
import { ViewForm } from "components/views"; import { ViewForm } from "components/views";
// types // types
import { IView } from "types"; import { ICurrentUserResponse, IView } from "types";
// fetch-keys // fetch-keys
import { VIEWS_LIST } from "constants/fetch-keys"; import { VIEWS_LIST } from "constants/fetch-keys";
@ -22,6 +22,7 @@ type Props = {
handleClose: () => void; handleClose: () => void;
data?: IView | null; data?: IView | null;
preLoadedData?: Partial<IView> | null; preLoadedData?: Partial<IView> | null;
user: ICurrentUserResponse | undefined;
}; };
export const CreateUpdateViewModal: React.FC<Props> = ({ export const CreateUpdateViewModal: React.FC<Props> = ({
@ -29,6 +30,7 @@ export const CreateUpdateViewModal: React.FC<Props> = ({
handleClose, handleClose,
data, data,
preLoadedData, preLoadedData,
user,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -45,7 +47,7 @@ export const CreateUpdateViewModal: React.FC<Props> = ({
query_data: payload.query, query_data: payload.query,
}; };
await viewsService await viewsService
.createView(workspaceSlug as string, projectId as string, payload) .createView(workspaceSlug as string, projectId as string, payload, user)
.then(() => { .then(() => {
mutate(VIEWS_LIST(projectId as string)); mutate(VIEWS_LIST(projectId as string));
handleClose(); handleClose();
@ -71,7 +73,7 @@ export const CreateUpdateViewModal: React.FC<Props> = ({
query_data: payload.query, query_data: payload.query,
}; };
await viewsService await viewsService
.updateView(workspaceSlug as string, projectId as string, data?.id ?? "", payloadData) .updateView(workspaceSlug as string, projectId as string, data?.id ?? "", payloadData, user)
.then((res) => { .then((res) => {
mutate<IView[]>( mutate<IView[]>(
VIEWS_LIST(projectId as string), VIEWS_LIST(projectId as string),

View File

@ -11,7 +11,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { CustomSelect, Input, PrimaryButton } from "components/ui"; import { CustomSelect, Input, PrimaryButton } from "components/ui";
// types // types
import { IWorkspace } from "types"; import { ICurrentUserResponse, IWorkspace } from "types";
// fetch-keys // fetch-keys
import { USER_WORKSPACES } from "constants/fetch-keys"; import { USER_WORKSPACES } from "constants/fetch-keys";
// constants // constants
@ -25,6 +25,7 @@ type Props = {
company_size: number | null; company_size: number | null;
}; };
setDefaultValues: Dispatch<SetStateAction<any>>; setDefaultValues: Dispatch<SetStateAction<any>>;
user: ICurrentUserResponse | undefined;
}; };
const restrictedUrls = [ const restrictedUrls = [
@ -44,6 +45,7 @@ export const CreateWorkspaceForm: React.FC<Props> = ({
onSubmit, onSubmit,
defaultValues, defaultValues,
setDefaultValues, setDefaultValues,
user,
}) => { }) => {
const [slugError, setSlugError] = useState(false); const [slugError, setSlugError] = useState(false);
const [invalidSlug, setInvalidSlug] = useState(false); const [invalidSlug, setInvalidSlug] = useState(false);
@ -66,7 +68,7 @@ export const CreateWorkspaceForm: React.FC<Props> = ({
if (res.status === true && !restrictedUrls.includes(formData.slug)) { if (res.status === true && !restrictedUrls.includes(formData.slug)) {
setSlugError(false); setSlugError(false);
await workspaceService await workspaceService
.createWorkspace(formData) .createWorkspace(formData, user)
.then((res) => { .then((res) => {
setToastAlert({ setToastAlert({
type: "success", type: "success",

View File

@ -15,7 +15,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui // ui
import { DangerButton, Input, SecondaryButton } from "components/ui"; import { DangerButton, Input, SecondaryButton } from "components/ui";
// types // types
import type { IWorkspace } from "types"; import type { ICurrentUserResponse, IWorkspace } from "types";
// fetch-keys // fetch-keys
import { USER_WORKSPACES } from "constants/fetch-keys"; import { USER_WORKSPACES } from "constants/fetch-keys";
@ -23,9 +23,10 @@ type Props = {
isOpen: boolean; isOpen: boolean;
data: IWorkspace | null; data: IWorkspace | null;
onClose: () => void; onClose: () => void;
user: ICurrentUserResponse | undefined;
}; };
export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose }) => { export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [confirmWorkspaceName, setConfirmWorkspaceName] = useState(""); const [confirmWorkspaceName, setConfirmWorkspaceName] = useState("");
@ -57,7 +58,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose })
setIsDeleteLoading(true); setIsDeleteLoading(true);
if (!data || !canDelete) return; if (!data || !canDelete) return;
await workspaceService await workspaceService
.deleteWorkspace(data.slug) .deleteWorkspace(data.slug, user)
.then(() => { .then(() => {
handleClose(); handleClose();
router.push("/"); router.push("/");

View File

@ -10,7 +10,7 @@ import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// types // types
import { IWorkspaceMemberInvitation } from "types"; import { ICurrentUserResponse, IWorkspaceMemberInvitation } from "types";
// fetch keys // fetch keys
import { WORKSPACE_INVITATIONS } from "constants/fetch-keys"; import { WORKSPACE_INVITATIONS } from "constants/fetch-keys";
// constants // constants
@ -21,6 +21,7 @@ type Props = {
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>; setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
workspace_slug: string; workspace_slug: string;
members: any[]; members: any[];
user: ICurrentUserResponse | undefined;
}; };
const defaultValues: Partial<IWorkspaceMemberInvitation> = { const defaultValues: Partial<IWorkspaceMemberInvitation> = {
@ -33,6 +34,7 @@ const SendWorkspaceInvitationModal: React.FC<Props> = ({
setIsOpen, setIsOpen,
workspace_slug, workspace_slug,
members, members,
user,
}) => { }) => {
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -54,7 +56,7 @@ const SendWorkspaceInvitationModal: React.FC<Props> = ({
const onSubmit = async (formData: IWorkspaceMemberInvitation) => { const onSubmit = async (formData: IWorkspaceMemberInvitation) => {
await workspaceService await workspaceService
.inviteWorkspace(workspace_slug, { emails: [formData] }) .inviteWorkspace(workspace_slug, { emails: [formData] }, user)
.then((res) => { .then((res) => {
setIsOpen(false); setIsOpen(false);
handleClose(); handleClose();
@ -101,7 +103,10 @@ const SendWorkspaceInvitationModal: React.FC<Props> = ({
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<div className="space-y-5"> <div className="space-y-5">
<div> <div>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-brand-base"> <Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-brand-base"
>
Members Members
</Dialog.Title> </Dialog.Title>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-brand-secondary">

View File

@ -46,7 +46,10 @@ const SingleInvitation: React.FC<Props> = ({
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="text-sm font-medium">{truncateText(invitation.workspace.name, 30)}</div> <div className="text-sm font-medium">{truncateText(invitation.workspace.name, 30)}</div>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-brand-secondary">
Invited by {invitation.workspace.owner.first_name} Invited by{" "}
{invitation.created_by_detail
? invitation.created_by_detail.first_name
: invitation.workspace.owner.first_name}
</p> </p>
</div> </div>
<div className="flex-shrink-0 self-center"> <div className="flex-shrink-0 self-center">

View File

@ -18,6 +18,7 @@ import {
IProjectMember, IProjectMember,
TIssueGroupByOptions, TIssueGroupByOptions,
TIssueOrderByOptions, TIssueOrderByOptions,
ICurrentUserResponse,
} from "types"; } from "types";
// fetch-keys // fetch-keys
import { import {
@ -26,6 +27,7 @@ import {
USER_PROJECT_VIEW, USER_PROJECT_VIEW,
VIEW_DETAILS, VIEW_DETAILS,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
import useUserAuth from "hooks/use-user-auth";
export const issueViewContext = createContext<ContextType>({} as ContextType); export const issueViewContext = createContext<ContextType>({} as ContextType);
@ -212,33 +214,54 @@ const saveCycleFilters = async (
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,
cycleId: string, cycleId: string,
state: any state: any,
user: ICurrentUserResponse | undefined
) => { ) => {
await cyclesService.patchCycle(workspaceSlug, projectId, cycleId, { await cyclesService.patchCycle(
...state, workspaceSlug,
}); projectId,
cycleId,
{
...state,
},
user
);
}; };
const saveModuleFilters = async ( const saveModuleFilters = async (
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,
moduleId: string, moduleId: string,
state: any state: any,
user: ICurrentUserResponse | undefined
) => { ) => {
await modulesService.patchModule(workspaceSlug, projectId, moduleId, { await modulesService.patchModule(
...state, workspaceSlug,
}); projectId,
moduleId,
{
...state,
},
user
);
}; };
const saveViewFilters = async ( const saveViewFilters = async (
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,
viewId: string, viewId: string,
state: any state: any,
user: ICurrentUserResponse | undefined
) => { ) => {
await viewsService.patchView(workspaceSlug, projectId, viewId, { await viewsService.patchView(
...state, workspaceSlug,
}); projectId,
viewId,
{
...state,
},
user
);
}; };
const setNewDefault = async (workspaceSlug: string, projectId: string, state: any) => { const setNewDefault = async (workspaceSlug: string, projectId: string, state: any) => {
@ -267,6 +290,8 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
const { user } = useUserAuth();
const { data: myViewProps, mutate: mutateMyViewProps } = useSWR( const { data: myViewProps, mutate: mutateMyViewProps } = useSWR(
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId as string) : null, workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -505,14 +530,20 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
}; };
}, false); }, false);
saveCycleFilters(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), { saveCycleFilters(
view_props: { workspaceSlug.toString(),
filters: { projectId.toString(),
...state.filters, cycleId.toString(),
...property, {
view_props: {
filters: {
...state.filters,
...property,
},
}, },
}, },
}); user
);
} else if (moduleId) { } else if (moduleId) {
mutateModuleDetails((prevData: any) => { mutateModuleDetails((prevData: any) => {
if (!prevData) return prevData; if (!prevData) return prevData;
@ -528,14 +559,20 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
}; };
}, false); }, false);
saveModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), { saveModuleFilters(
view_props: { workspaceSlug.toString(),
filters: { projectId.toString(),
...state.filters, moduleId.toString(),
...property, {
view_props: {
filters: {
...state.filters,
...property,
},
}, },
}, },
}); user
);
} else if (viewId) { } else if (viewId) {
mutateViewDetails((prevData: any) => { mutateViewDetails((prevData: any) => {
if (!prevData) return prevData; if (!prevData) return prevData;
@ -548,12 +585,18 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
}; };
}, false); }, false);
if (saveToServer) if (saveToServer)
saveViewFilters(workspaceSlug as string, projectId as string, viewId as string, { saveViewFilters(
query_data: { workspaceSlug as string,
...state.filters, projectId as string,
...property, viewId as string,
{
query_data: {
...state.filters,
...property,
},
}, },
}); user
);
} else { } else {
mutateMyViewProps((prevData) => { mutateMyViewProps((prevData) => {
if (!prevData) return prevData; if (!prevData) return prevData;

View File

@ -6,6 +6,8 @@ import useSWR from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// hooks
import useUserAuth from "hooks/use-user-auth";
// headless ui // headless ui
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// services // services
@ -35,6 +37,8 @@ const Analytics = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
const { control, watch, setValue } = useForm<IAnalyticsParams>({ defaultValues }); const { control, watch, setValue } = useForm<IAnalyticsParams>({ defaultValues });
const params: IAnalyticsParams = { const params: IAnalyticsParams = {
@ -59,7 +63,7 @@ const Analytics = () => {
? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS"
: "WORKSPACE_CUSTOM_ANALYTICS"; : "WORKSPACE_CUSTOM_ANALYTICS";
trackEventServices.trackAnalyticsEvent(eventPayload, eventType); trackEventServices.trackAnalyticsEvent(eventPayload, eventType, user);
}; };
useEffect(() => { useEffect(() => {
@ -67,7 +71,8 @@ const Analytics = () => {
trackEventServices.trackAnalyticsEvent( trackEventServices.trackAnalyticsEvent(
{ workspaceSlug: workspaceSlug?.toString() }, { workspaceSlug: workspaceSlug?.toString() },
"WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS",
user
); );
}, [workspaceSlug]); }, [workspaceSlug]);
@ -119,6 +124,7 @@ const Analytics = () => {
params={params} params={params}
control={control} control={control}
setValue={setValue} setValue={setValue}
user={user}
fullScreen fullScreen
/> />
</Tab.Panel> </Tab.Panel>

View File

@ -19,6 +19,7 @@ import cycleServices from "services/cycles.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { AnalyticsProjectModal } from "components/analytics"; import { AnalyticsProjectModal } from "components/analytics";
// ui // ui
@ -44,6 +45,8 @@ const SingleCycle: React.FC = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId } = router.query; const { workspaceSlug, projectId, cycleId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: activeProject } = useSWR( const { data: activeProject } = useSWR(
@ -94,7 +97,7 @@ const SingleCycle: React.FC = () => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await issuesService await issuesService
.addIssueToCycle(workspaceSlug as string, projectId as string, cycleId as string, data) .addIssueToCycle(workspaceSlug as string, projectId as string, cycleId as string, data, user)
.then(() => { .then(() => {
mutate(CYCLE_ISSUES(cycleId as string)); mutate(CYCLE_ISSUES(cycleId as string));
}) })
@ -185,6 +188,7 @@ const SingleCycle: React.FC = () => {
cycle={cycleDetails} cycle={cycleDetails}
isOpen={cycleSidebar} isOpen={cycleSidebar}
isCompleted={cycleStatus === "completed" ?? false} isCompleted={cycleStatus === "completed" ?? false}
user={user}
/> />
</ProjectAuthorizationWrapper> </ProjectAuthorizationWrapper>
</IssueViewContextProvider> </IssueViewContextProvider>

View File

@ -8,6 +8,7 @@ import useSWR from "swr";
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// hooks // hooks
import useLocalStorage from "hooks/use-local-storage"; import useLocalStorage from "hooks/use-local-storage";
import useUserAuth from "hooks/use-user-auth";
// services // services
import cycleService from "services/cycles.service"; import cycleService from "services/cycles.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
@ -62,6 +63,8 @@ const ProjectCycles: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { data: activeProject } = useSWR( const { data: activeProject } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -110,6 +113,7 @@ const ProjectCycles: NextPage = () => {
isOpen={createUpdateCycleModal} isOpen={createUpdateCycleModal}
handleClose={() => setCreateUpdateCycleModal(false)} handleClose={() => setCreateUpdateCycleModal(false)}
data={selectedCycle} data={selectedCycle}
user={user}
/> />
<div className="space-y-5 p-8 h-full flex flex-col overflow-hidden"> <div className="space-y-5 p-8 h-full flex flex-col overflow-hidden">
<div className="flex gap-4 justify-between"> <div className="flex gap-4 justify-between">

View File

@ -7,6 +7,8 @@ import useSWR, { mutate } from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// layouts // layouts
@ -50,6 +52,8 @@ const IssueDetailsPage: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
const { user } = useUserAuth();
const { data: issueDetails, mutate: mutateIssueDetails } = useSWR<IIssue | undefined>( const { data: issueDetails, mutate: mutateIssueDetails } = useSWR<IIssue | undefined>(
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
workspaceSlug && projectId && issueId workspaceSlug && projectId && issueId
@ -92,7 +96,7 @@ const IssueDetailsPage: NextPage = () => {
const payload = { ...formData }; const payload = { ...formData };
await issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.then((res) => { .then((res) => {
mutateIssueDetails(); mutateIssueDetails();
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
@ -192,7 +196,7 @@ const IssueDetailsPage: NextPage = () => {
) : null} ) : null}
<IssueDescriptionForm issue={issueDetails} handleFormSubmit={submitChanges} /> <IssueDescriptionForm issue={issueDetails} handleFormSubmit={submitChanges} />
<div className="mt-2 space-y-2"> <div className="mt-2 space-y-2">
<SubIssuesList parentIssue={issueDetails} /> <SubIssuesList parentIssue={issueDetails} user={user} />
</div> </div>
</div> </div>
<div className="flex flex-col gap-3 py-3"> <div className="flex flex-col gap-3 py-3">
@ -204,8 +208,8 @@ const IssueDetailsPage: NextPage = () => {
</div> </div>
<div className="space-y-5 pt-3"> <div className="space-y-5 pt-3">
<h3 className="text-lg text-brand-base">Comments/Activity</h3> <h3 className="text-lg text-brand-base">Comments/Activity</h3>
<IssueActivitySection /> <IssueActivitySection user={user} />
<AddComment /> <AddComment user={user} />
</div> </div>
</div> </div>
<div className="basis-1/3 space-y-5 border-l border-brand-base p-5"> <div className="basis-1/3 space-y-5 border-l border-brand-base p-5">

View File

@ -17,6 +17,7 @@ import modulesService from "services/modules.service";
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// layouts // layouts
import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// contexts // contexts
@ -49,6 +50,8 @@ const SingleModule: React.FC = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query; const { workspaceSlug, projectId, moduleId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: issues } = useSWR( const { data: issues } = useSWR(
@ -95,7 +98,13 @@ const SingleModule: React.FC = () => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
await modulesService await modulesService
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleId as string, data) .addIssuesToModule(
workspaceSlug as string,
projectId as string,
moduleId as string,
data,
user
)
.then(() => mutate(MODULE_ISSUES(moduleId as string))) .then(() => mutate(MODULE_ISSUES(moduleId as string)))
.catch(() => .catch(() =>
setToastAlert({ setToastAlert({
@ -186,6 +195,7 @@ const SingleModule: React.FC = () => {
module={moduleDetails} module={moduleDetails}
isOpen={moduleSidebar} isOpen={moduleSidebar}
moduleIssues={moduleIssues} moduleIssues={moduleIssues}
user={user}
/> />
</ProjectAuthorizationWrapper> </ProjectAuthorizationWrapper>
</IssueViewContextProvider> </IssueViewContextProvider>

View File

@ -6,6 +6,8 @@ import useSWR from "swr";
// layouts // layouts
import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import modulesService from "services/modules.service"; import modulesService from "services/modules.service";
@ -37,6 +39,8 @@ const ProjectModules: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { data: activeProject } = useSWR( const { data: activeProject } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -89,6 +93,7 @@ const ProjectModules: NextPage = () => {
isOpen={createUpdateModule} isOpen={createUpdateModule}
setIsOpen={setCreateUpdateModule} setIsOpen={setCreateUpdateModule}
data={selectedModule} data={selectedModule}
user={user}
/> />
{modules ? ( {modules ? (
modules.length > 0 ? ( modules.length > 0 ? (
@ -126,6 +131,7 @@ const ProjectModules: NextPage = () => {
key={module.id} key={module.id}
module={module} module={module}
handleEditModule={() => handleEditModule(module)} handleEditModule={() => handleEditModule(module)}
user={user}
/> />
))} ))}
</div> </div>

View File

@ -116,7 +116,7 @@ const SinglePage: NextPage = () => {
if (!formData.name || formData.name.length === 0 || formData.name === "") return; if (!formData.name || formData.name.length === 0 || formData.name === "") return;
await pagesService await pagesService
.patchPage(workspaceSlug as string, projectId as string, pageId as string, formData) .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData, user)
.then(() => { .then(() => {
mutate<IPage>( mutate<IPage>(
PAGE_DETAILS(pageId as string), PAGE_DETAILS(pageId as string),
@ -143,7 +143,7 @@ const SinglePage: NextPage = () => {
); );
await pagesService await pagesService
.patchPage(workspaceSlug as string, projectId as string, pageId as string, formData) .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData, user)
.then(() => { .then(() => {
mutate(PAGE_DETAILS(pageId as string)); mutate(PAGE_DETAILS(pageId as string));
}); });
@ -237,7 +237,8 @@ const SinglePage: NextPage = () => {
result.draggableId, result.draggableId,
{ {
sort_order: newSortOrder, sort_order: newSortOrder,
} },
user
); );
}; };
@ -529,6 +530,7 @@ const SinglePage: NextPage = () => {
block={block} block={block}
projectDetails={projectDetails} projectDetails={projectDetails}
index={index} index={index}
user={user}
/> />
))} ))}
{provided.placeholder} {provided.placeholder}
@ -542,6 +544,7 @@ const SinglePage: NextPage = () => {
<CreateUpdateBlockInline <CreateUpdateBlockInline
handleClose={() => setCreateBlockForm(false)} handleClose={() => setCreateBlockForm(false)}
focus="name" focus="name"
user={user}
/> />
</div> </div>
)} )}
@ -550,6 +553,7 @@ const SinglePage: NextPage = () => {
isOpen={labelModal} isOpen={labelModal}
handleClose={() => setLabelModal(false)} handleClose={() => setLabelModal(false)}
projectId={projectId} projectId={projectId}
user={user}
/> />
)} )}
</> </>
@ -562,7 +566,7 @@ const SinglePage: NextPage = () => {
</div> </div>
</div> </div>
<div> <div>
<CreateBlock /> <CreateBlock user={user} />
</div> </div>
</div> </div>
) : ( ) : (

View File

@ -27,6 +27,7 @@ import { TPageViewProps } from "types";
import type { NextPage } from "next"; import type { NextPage } from "next";
// fetch-keys // fetch-keys
import { PROJECT_DETAILS } from "constants/fetch-keys"; import { PROJECT_DETAILS } from "constants/fetch-keys";
import useUserAuth from "hooks/use-user-auth";
const AllPagesList = dynamic<TPagesListProps>( const AllPagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.AllPagesList), () => import("components/pages").then((a) => a.AllPagesList),
@ -66,6 +67,8 @@ const ProjectPages: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { storedValue: pageTab, setValue: setPageTab } = useLocalStorage("pageTab", "Recent"); const { storedValue: pageTab, setValue: setPageTab } = useLocalStorage("pageTab", "Recent");
const { data: projectDetails } = useSWR( const { data: projectDetails } = useSWR(
@ -98,6 +101,7 @@ const ProjectPages: NextPage = () => {
<CreateUpdatePageModal <CreateUpdatePageModal
isOpen={createUpdatePageModal} isOpen={createUpdatePageModal}
handleClose={() => setCreateUpdatePageModal(false)} handleClose={() => setCreateUpdatePageModal(false)}
user={user}
/> />
<ProjectAuthorizationWrapper <ProjectAuthorizationWrapper
breadcrumbs={ breadcrumbs={

View File

@ -13,6 +13,7 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { SettingsHeader } from "components/project"; import { SettingsHeader } from "components/project";
// ui // ui
@ -35,6 +36,8 @@ const ControlSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { data: projectDetails } = useSWR<IProject>( const { data: projectDetails } = useSWR<IProject>(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -65,7 +68,7 @@ const ControlSettings: NextPage = () => {
}; };
await projectService await projectService
.updateProject(workspaceSlug as string, projectId as string, payload) .updateProject(workspaceSlug as string, projectId as string, payload, user)
.then((res) => { .then((res) => {
mutate(PROJECT_DETAILS(projectId as string)); mutate(PROJECT_DETAILS(projectId as string));
mutate(PROJECTS_LIST(workspaceSlug as string)); mutate(PROJECTS_LIST(workspaceSlug as string));

View File

@ -16,6 +16,7 @@ import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates"
import { SettingsHeader } from "components/project"; import { SettingsHeader } from "components/project";
//hooks //hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui // ui
import { EmptyState, Loader, SecondaryButton } from "components/ui"; import { EmptyState, Loader, SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -37,6 +38,8 @@ const EstimatesSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { projectDetails } = useProjectDetails(); const { projectDetails } = useProjectDetails();
@ -63,7 +66,7 @@ const EstimatesSettings: NextPage = () => {
); );
estimatesService estimatesService
.deleteEstimate(workspaceSlug as string, projectId as string, estimateId) .deleteEstimate(workspaceSlug as string, projectId as string, estimateId, user)
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
@ -87,7 +90,7 @@ const EstimatesSettings: NextPage = () => {
); );
projectService projectService
.updateProject(workspaceSlug as string, projectId as string, { estimate: null }) .updateProject(workspaceSlug as string, projectId as string, { estimate: null }, user)
.catch(() => .catch(() =>
setToastAlert({ setToastAlert({
type: "error", type: "error",
@ -106,6 +109,7 @@ const EstimatesSettings: NextPage = () => {
setEstimateFormOpen(false); setEstimateFormOpen(false);
setEstimateToUpdate(undefined); setEstimateToUpdate(undefined);
}} }}
user={user}
/> />
<ProjectAuthorizationWrapper <ProjectAuthorizationWrapper
breadcrumbs={ breadcrumbs={
@ -149,6 +153,7 @@ const EstimatesSettings: NextPage = () => {
estimate={estimate} estimate={estimate}
editEstimate={(estimate) => editEstimate(estimate)} editEstimate={(estimate) => editEstimate(estimate)}
handleEstimateDelete={(estimateId) => removeEstimate(estimateId)} handleEstimateDelete={(estimateId) => removeEstimate(estimateId)}
user={user}
/> />
))} ))}
</section> </section>

View File

@ -11,6 +11,7 @@ import trackEventServices, { MiscellaneousEventType } from "services/track-event
import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { SettingsHeader } from "components/project"; import { SettingsHeader } from "components/project";
// ui // ui
@ -75,6 +76,8 @@ const FeaturesSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: projectDetails } = useSWR( const { data: projectDetails } = useSWR(
@ -134,7 +137,7 @@ const FeaturesSettings: NextPage = () => {
}); });
await projectService await projectService
.updateProject(workspaceSlug as string, projectId as string, formData) .updateProject(workspaceSlug as string, projectId as string, formData, user)
.then(() => { .then(() => {
mutate( mutate(
projectDetails.is_favorite projectDetails.is_favorite
@ -194,7 +197,8 @@ const FeaturesSettings: NextPage = () => {
}, },
!projectDetails?.[feature.property as keyof IProject] !projectDetails?.[feature.property as keyof IProject]
? getEventType(feature.title, true) ? getEventType(feature.title, true)
: getEventType(feature.title, false) : getEventType(feature.title, false),
user
); );
handleSubmit({ handleSubmit({
[feature.property]: !projectDetails?.[feature.property as keyof IProject], [feature.property]: !projectDetails?.[feature.property as keyof IProject],

View File

@ -17,6 +17,7 @@ import { ImagePickerPopover } from "components/core";
import EmojiIconPicker from "components/emoji-icon-picker"; import EmojiIconPicker from "components/emoji-icon-picker";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui // ui
import { import {
Input, Input,
@ -45,6 +46,8 @@ const defaultValues: Partial<IProject> = {
const GeneralSettings: NextPage = () => { const GeneralSettings: NextPage = () => {
const [selectProject, setSelectedProject] = useState<string | null>(null); const [selectProject, setSelectedProject] = useState<string | null>(null);
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const router = useRouter(); const router = useRouter();
@ -83,7 +86,7 @@ const GeneralSettings: NextPage = () => {
if (!workspaceSlug || !projectDetails) return; if (!workspaceSlug || !projectDetails) return;
await projectService await projectService
.updateProject(workspaceSlug as string, projectDetails.id, payload) .updateProject(workspaceSlug as string, projectDetails.id, payload, user)
.then((res) => { .then((res) => {
mutate<IProject>( mutate<IProject>(
PROJECT_DETAILS(projectDetails.id), PROJECT_DETAILS(projectDetails.id),
@ -154,6 +157,7 @@ const GeneralSettings: NextPage = () => {
onSuccess={() => { onSuccess={() => {
router.push(`/${workspaceSlug}/projects`); router.push(`/${workspaceSlug}/projects`);
}} }}
user={user}
/> />
<form onSubmit={handleSubmit(onSubmit)} className="p-8"> <form onSubmit={handleSubmit(onSubmit)} className="p-8">
<SettingsHeader /> <SettingsHeader />

View File

@ -4,6 +4,8 @@ import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
@ -47,6 +49,8 @@ const LabelsSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const scrollToRef = useRef<HTMLDivElement>(null); const scrollToRef = useRef<HTMLDivElement>(null);
const { data: projectDetails } = useSWR( const { data: projectDetails } = useSWR(
@ -85,11 +89,13 @@ const LabelsSettings: NextPage = () => {
isOpen={labelsListModal} isOpen={labelsListModal}
handleClose={() => setLabelsListModal(false)} handleClose={() => setLabelsListModal(false)}
parent={parentLabel} parent={parentLabel}
user={user}
/> />
<DeleteLabelModal <DeleteLabelModal
isOpen={!!selectDeleteLabel} isOpen={!!selectDeleteLabel}
data={selectDeleteLabel ?? null} data={selectDeleteLabel ?? null}
onClose={() => setSelectDeleteLabel(null)} onClose={() => setSelectDeleteLabel(null)}
user={user}
/> />
<ProjectAuthorizationWrapper <ProjectAuthorizationWrapper
breadcrumbs={ breadcrumbs={
@ -160,6 +166,7 @@ const LabelsSettings: NextPage = () => {
}); });
}} }}
handleLabelDelete={() => setSelectDeleteLabel(label)} handleLabelDelete={() => setSelectDeleteLabel(label)}
user={user}
/> />
); );
}) })

View File

@ -135,6 +135,7 @@ const MembersSettings: NextPage = () => {
isOpen={inviteModal} isOpen={inviteModal}
setIsOpen={setInviteModal} setIsOpen={setInviteModal}
members={members} members={members}
user={user}
/> />
<ProjectAuthorizationWrapper <ProjectAuthorizationWrapper
breadcrumbs={ breadcrumbs={

View File

@ -8,6 +8,7 @@ import useSWR from "swr";
import stateService from "services/state.service"; import stateService from "services/state.service";
// hooks // hooks
import useProjectDetails from "hooks/use-project-details"; import useProjectDetails from "hooks/use-project-details";
import useUserAuth from "hooks/use-user-auth";
// layouts // layouts
import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// components // components
@ -38,6 +39,8 @@ const StatesSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { projectDetails } = useProjectDetails(); const { projectDetails } = useProjectDetails();
const { data: states } = useSWR( const { data: states } = useSWR(
@ -55,6 +58,7 @@ const StatesSettings: NextPage = () => {
isOpen={!!selectDeleteState} isOpen={!!selectDeleteState}
data={statesList?.find((s) => s.id === selectDeleteState) ?? null} data={statesList?.find((s) => s.id === selectDeleteState) ?? null}
onClose={() => setSelectDeleteState(null)} onClose={() => setSelectDeleteState(null)}
user={user}
/> />
<ProjectAuthorizationWrapper <ProjectAuthorizationWrapper
breadcrumbs={ breadcrumbs={
@ -100,6 +104,7 @@ const StatesSettings: NextPage = () => {
}} }}
data={null} data={null}
selectedGroup={key as keyof StateGroup} selectedGroup={key as keyof StateGroup}
user={user}
/> />
)} )}
{orderedStateGroups[key].map((state, index) => {orderedStateGroups[key].map((state, index) =>
@ -111,6 +116,7 @@ const StatesSettings: NextPage = () => {
statesList={statesList} statesList={statesList}
handleEditState={() => setSelectedState(state.id)} handleEditState={() => setSelectedState(state.id)}
handleDeleteState={() => setSelectDeleteState(state.id)} handleDeleteState={() => setSelectDeleteState(state.id)}
user={user}
/> />
) : ( ) : (
<div <div
@ -126,6 +132,7 @@ const StatesSettings: NextPage = () => {
statesList?.find((state) => state.id === selectedState) ?? null statesList?.find((state) => state.id === selectedState) ?? null
} }
selectedGroup={key as keyof StateGroup} selectedGroup={key as keyof StateGroup}
user={user}
/> />
</div> </div>
) )

View File

@ -4,6 +4,8 @@ import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services // services
import viewsService from "services/views.service"; import viewsService from "services/views.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
@ -34,6 +36,8 @@ const ProjectViews: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { data: activeProject } = useSWR( const { data: activeProject } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -86,11 +90,13 @@ const ProjectViews: NextPage = () => {
isOpen={createUpdateViewModal} isOpen={createUpdateViewModal}
handleClose={() => setCreateUpdateViewModal(false)} handleClose={() => setCreateUpdateViewModal(false)}
data={selectedViewToUpdate} data={selectedViewToUpdate}
user={user}
/> />
<DeleteViewModal <DeleteViewModal
isOpen={deleteViewModal} isOpen={deleteViewModal}
data={selectedViewToDelete} data={selectedViewToDelete}
setIsOpen={setDeleteViewModal} setIsOpen={setDeleteViewModal}
user={user}
/> />
{views ? ( {views ? (
views.length > 0 ? ( views.length > 0 ? (

View File

@ -9,6 +9,7 @@ import projectService from "services/project.service";
// hooks // hooks
import useProjects from "hooks/use-projects"; import useProjects from "hooks/use-projects";
import useWorkspaces from "hooks/use-workspaces"; import useWorkspaces from "hooks/use-workspaces";
import useUserAuth from "hooks/use-user-auth";
// layouts // layouts
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
// components // components
@ -30,6 +31,8 @@ const ProjectsPage: NextPage = () => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
// context data // context data
const { activeWorkspace } = useWorkspaces(); const { activeWorkspace } = useWorkspaces();
const { projects } = useProjects(); const { projects } = useProjects();
@ -81,6 +84,7 @@ const ProjectsPage: NextPage = () => {
isOpen={!!deleteProject} isOpen={!!deleteProject}
onClose={() => setDeleteProject(null)} onClose={() => setDeleteProject(null)}
data={projects?.find((item) => item.id === deleteProject) ?? null} data={projects?.find((item) => item.id === deleteProject) ?? null}
user={user}
/> />
{projects ? ( {projects ? (
<div className="p-8"> <div className="p-8">

View File

@ -12,6 +12,7 @@ import workspaceService from "services/workspace.service";
import fileService from "services/file.service"; import fileService from "services/file.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// layouts // layouts
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
import SettingsNavbar from "layouts/settings-navbar"; import SettingsNavbar from "layouts/settings-navbar";
@ -49,6 +50,8 @@ const WorkspaceSettings: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { user } = useUserAuth();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: activeWorkspace } = useSWR( const { data: activeWorkspace } = useSWR(
@ -82,7 +85,7 @@ const WorkspaceSettings: NextPage = () => {
}; };
await workspaceService await workspaceService
.updateWorkspace(activeWorkspace.slug, payload) .updateWorkspace(activeWorkspace.slug, payload, user)
.then((res) => { .then((res) => {
mutate<IWorkspace[]>(USER_WORKSPACES, (prevData) => mutate<IWorkspace[]>(USER_WORKSPACES, (prevData) =>
prevData?.map((workspace) => (workspace.id === res.id ? res : workspace)) prevData?.map((workspace) => (workspace.id === res.id ? res : workspace))
@ -114,7 +117,7 @@ const WorkspaceSettings: NextPage = () => {
fileService.deleteFile(asset).then(() => { fileService.deleteFile(asset).then(() => {
workspaceService workspaceService
.updateWorkspace(activeWorkspace.slug, { logo: "" }) .updateWorkspace(activeWorkspace.slug, { logo: "" }, user)
.then((res) => { .then((res) => {
setToastAlert({ setToastAlert({
type: "success", type: "success",
@ -169,6 +172,7 @@ const WorkspaceSettings: NextPage = () => {
setIsOpen(false); setIsOpen(false);
}} }}
data={activeWorkspace ?? null} data={activeWorkspace ?? null}
user={user}
/> />
<div className="p-8"> <div className="p-8">
<SettingsHeader /> <SettingsHeader />

View File

@ -135,6 +135,7 @@ const MembersSettings: NextPage = () => {
setIsOpen={setInviteModal} setIsOpen={setInviteModal}
workspace_slug={workspaceSlug as string} workspace_slug={workspaceSlug as string}
members={members} members={members}
user={user}
/> />
<WorkspaceAuthorizationLayout <WorkspaceAuthorizationLayout
breadcrumbs={ breadcrumbs={

View File

@ -10,28 +10,12 @@ const jitsu = createClient({
}); });
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { eventName, extra } = req.body; const { eventName, user, extra } = req.body;
if (!eventName) { if (!eventName) {
return res.status(400).json({ message: "Bad request" }); return res.status(400).json({ message: "Bad request" });
} }
const cookie = convertCookieStringToObject(req.headers.cookie);
const accessToken = cookie?.accessToken;
if (!accessToken) return res.status(401).json({ message: "Unauthorized" });
const user = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/users/me/`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
})
.then((res) => res.json())
.then((data) => data.user)
.catch(() => res.status(401).json({ message: "Unauthorized" }));
if (!user) return res.status(401).json({ message: "Unauthorized" }); if (!user) return res.status(401).json({ message: "Unauthorized" });
// TODO: cache user info // TODO: cache user info

View File

@ -47,6 +47,7 @@ const CreateWorkspace: NextPage = () => {
defaultValues={defaultValues} defaultValues={defaultValues}
setDefaultValues={() => {}} setDefaultValues={() => {}}
onSubmit={(res) => router.push(`/${res.slug}`)} onSubmit={(res) => router.push(`/${res.slug}`)}
user={user}
/> />
</div> </div>
</div> </div>

View File

@ -95,21 +95,21 @@ const HomePage: NextPage = () => {
<Spinner /> <Spinner />
</div> </div>
) : ( ) : (
<div className="flex h-screen w-full items-center justify-center overflow-auto bg-gray-50"> <div className="flex h-screen w-full items-center justify-center overflow-auto">
<div className="flex min-h-full w-full flex-col justify-center py-12 px-6 lg:px-8"> <div className="flex min-h-full w-full flex-col justify-center py-12 px-6 lg:px-8">
<div className="flex flex-col gap-10 sm:mx-auto sm:w-full sm:max-w-md"> <div className="flex flex-col gap-10 sm:mx-auto sm:w-full sm:max-w-md">
<div className="flex flex-col items-center justify-center gap-10"> <div className="flex flex-col items-center justify-center gap-10">
<Image src={Logo} height={80} width={80} alt="Plane Web Logo" /> <Image src={Logo} height={80} width={80} alt="Plane Web Logo" />
<div className="text-center text-xl font-medium text-black"> <div className="text-center text-xl font-medium text-brand-base">
Sign In to your Plane Account Sign In to your Plane Account
</div> </div>
</div> </div>
<div className="flex flex-col rounded-[10px] bg-white shadow-md"> <div className="flex flex-col rounded-[10px] bg-brand-base shadow-md">
{parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0") ? ( {parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0") ? (
<> <>
<EmailCodeForm /> <EmailCodeForm />
<div className="flex flex-col gap-3 py-5 px-5 border-t items-center justify-center border-gray-300 "> <div className="flex flex-col items-center justify-center gap-3 border-t border-brand-base py-5 px-5">
<GoogleLoginButton handleSignIn={handleGoogleSignIn} /> <GoogleLoginButton handleSignIn={handleGoogleSignIn} />
<GithubLoginButton handleSignIn={handleGithubSignIn} /> <GithubLoginButton handleSignIn={handleGithubSignIn} />
</div> </div>

View File

@ -124,7 +124,7 @@ const OnBoard: NextPage = () => {
</div> </div>
</div> </div>
) : workspaces && workspaces.length > 0 ? ( ) : workspaces && workspaces.length > 0 ? (
<div className="flex flex-col gap-y-3"> <div className="flex flex-col w-full overflow-auto gap-y-3">
<h2 className="mb-4 text-xl font-medium">Your workspaces</h2> <h2 className="mb-4 text-xl font-medium">Your workspaces</h2>
{workspaces.map((workspace) => ( {workspaces.map((workspace) => (
<Link key={workspace.id} href={workspace.slug}> <Link key={workspace.id} href={workspace.slug}>

View File

@ -49,18 +49,18 @@ const MagicSignIn: NextPage = () => {
return ( return (
<DefaultLayout> <DefaultLayout>
<div className="flex h-screen w-full items-center justify-center overflow-auto bg-gray-50"> <div className="h-screen w-full overflow-auto bg-brand-surface-1">
{isSigningIn ? ( {isSigningIn ? (
<div className="flex h-full w-full flex-col items-center justify-center gap-y-2"> <div className="flex h-full w-full flex-col items-center justify-center gap-y-2">
<h2 className="text-4xl">Signing you in...</h2> <h2 className="text-4xl">Signing you in...</h2>
<p className="text-sm text-gray-600"> <p className="text-sm text-brand-secondary">
Please wait while we are preparing your take off. Please wait while we are preparing your take off.
</p> </p>
</div> </div>
) : errorSigningIn ? ( ) : errorSigningIn ? (
<div className="flex h-full w-full flex-col items-center justify-center gap-y-2"> <div className="flex h-full w-full flex-col items-center justify-center gap-y-2">
<h2 className="text-4xl">Error</h2> <h2 className="text-4xl">Error</h2>
<p className="text-sm text-gray-600"> <p className="text-sm text-brand-secondary">
{errorSigningIn}. {errorSigningIn}.
<span <span
className="cursor-pointer underline" className="cursor-pointer underline"
@ -90,7 +90,7 @@ const MagicSignIn: NextPage = () => {
) : ( ) : (
<div className="flex h-full w-full flex-col items-center justify-center gap-y-2"> <div className="flex h-full w-full flex-col items-center justify-center gap-y-2">
<h2 className="text-4xl">Success</h2> <h2 className="text-4xl">Success</h2>
<p className="text-sm text-gray-600">Redirecting you to the app...</p> <p className="text-sm text-brand-secondary">Redirecting you to the app...</p>
</div> </div>
)} )}
</div> </div>

View File

@ -53,9 +53,9 @@ const Onboarding: NextPage = () => {
{step === 1 ? ( {step === 1 ? (
<UserDetails user={user} setStep={setStep} setUserRole={setUserRole} /> <UserDetails user={user} setStep={setStep} setUserRole={setUserRole} />
) : step === 2 ? ( ) : step === 2 ? (
<Workspace setStep={setStep} setWorkspace={setWorkspace} /> <Workspace setStep={setStep} setWorkspace={setWorkspace} user={user} />
) : ( ) : (
<InviteMembers setStep={setStep} workspace={workspace} /> <InviteMembers setStep={setStep} workspace={workspace} user={user} />
)} )}
</div> </div>
) : ( ) : (
@ -80,7 +80,7 @@ const Onboarding: NextPage = () => {
onClick={() => { onClick={() => {
if (step === 8) { if (step === 8) {
userService userService
.updateUserOnBoard({ userRole }) .updateUserOnBoard({ userRole }, user)
.then(async () => { .then(async () => {
mutate<ICurrentUserResponse>( mutate<ICurrentUserResponse>(
CURRENT_USER, CURRENT_USER,

Some files were not shown because too many files have changed in this diff Show More