Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: user auth layer #749

Merged
merged 4 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion apps/app/components/core/board-view/single-issue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import useToast from "hooks/use-toast";
import {
ViewAssigneeSelect,
ViewDueDateSelect,
ViewEstimateSelect,
ViewPrioritySelect,
ViewStateSelect,
} from "components/issues/view-select";
} from "components/issues";
// ui
import { ContextMenu, CustomMenu } from "components/ui";
// icons
Expand All @@ -48,6 +49,7 @@ import {
MODULE_ISSUES_WITH_PARAMS,
PROJECT_ISSUES_LIST_WITH_PARAMS,
} from "constants/fetch-keys";
import useEstimateOption from "hooks/use-estimate-option";

type Props = {
type?: string;
Expand Down Expand Up @@ -90,6 +92,8 @@ export const SingleBoardIssue: React.FC<Props> = ({

const { orderBy, params } = useIssuesView();

const { estimateValue } = useEstimateOption(issue.estimate_point);

const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;

Expand Down Expand Up @@ -342,6 +346,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
selfPositioned
/>
)}
{properties.estimate && (
<ViewEstimateSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
isNotAllowed={isNotAllowed}
selfPositioned
/>
)}
</div>
</div>
</div>
Expand Down
151 changes: 82 additions & 69 deletions apps/app/components/estimates/single-estimate.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
import React, { useState } from "react";

// ui
import { CustomMenu, PrimaryButton } from "components/ui";
// types
import { IEstimate, IProject } from "types";
//icons
import { PencilIcon, TrashIcon, SquaresPlusIcon, ListBulletIcon } from "@heroicons/react/24/outline";

import useSWR, { mutate } from "swr";
import { useRouter } from "next/router";

import useToast from "hooks/use-toast";
import useSWR from "swr";

// services
import estimatesService from "services/estimates.service";
import projectService from "services/project.service";

import { EstimatePointsModal } from "./estimate-points-modal";
import { useRouter } from "next/router";

// hooks
import useToast from "hooks/use-toast";
import useProjectDetails from "hooks/use-project-details";
// components
import { EstimatePointsModal } from "components/estimates";
// ui
import { CustomMenu } from "components/ui";
//icons
import {
PencilIcon,
TrashIcon,
SquaresPlusIcon,
ListBulletIcon,
} from "@heroicons/react/24/outline";
// types
import { IEstimate, IProject } from "types";
// fetch-keys
import { ESTIMATE_POINTS_LIST } from "constants/fetch-keys";
import { PlusIcon } from "components/icons";

interface IEstimatePoints {
key: string;
value: string;
}

type Props = {
estimate: IEstimate;
editEstimate: (estimate: IEstimate) => void;
handleEstimateDelete: (estimateId: string) => void;
activeEstimate: IEstimate | null;
setActiveEstimate: React.Dispatch<React.SetStateAction<IEstimate | null>>;
};

export const SingleEstimate: React.FC<Props> = ({
estimate,
editEstimate,
handleEstimateDelete,
activeEstimate,
setActiveEstimate,
}) => {
const [isEstimatePointsModalOpen, setIsEstimatePointsModalOpen] = useState(false);

Expand All @@ -47,6 +44,8 @@ export const SingleEstimate: React.FC<Props> = ({

const { setToastAlert } = useToast();

const { projectDetails, mutateProjectDetails } = useProjectDetails();

const { data: estimatePoints } = useSWR(
workspaceSlug && projectId ? ESTIMATE_POINTS_LIST(estimate.id) : null,
workspaceSlug && projectId
Expand All @@ -59,12 +58,19 @@ export const SingleEstimate: React.FC<Props> = ({
: null
);

const handleActiveEstimate = async () => {
if (!workspaceSlug || !projectId || !estimate) return;
const payload: Partial<IProject> = {
const handleUseEstimate = async () => {
if (!workspaceSlug || !projectId) return;

const payload = {
estimate: estimate.id,
};
setActiveEstimate(estimate);

mutateProjectDetails((prevData) => {
if (!prevData) return prevData;

return { ...prevData, estimate: estimate.id };
}, false);

await projectService
.updateProject(workspaceSlug as string, projectId as string, payload)
.catch(() => {
Expand All @@ -77,56 +83,63 @@ export const SingleEstimate: React.FC<Props> = ({
};

return (
<div className="divide-y">
<>
<EstimatePointsModal
isOpen={isEstimatePointsModalOpen}
estimate={estimate}
onClose={() => setIsEstimatePointsModalOpen(false)}
/>
<div className="gap-2 space-y-3 my-3 bg-white">
<div className="gap-2 py-3">
<div className="flex justify-between items-center">
<div className="items-start">
<h6 className="font-medium text-base w-[40vw] truncate">{estimate.name}</h6>
<div>
<h6 className="flex items-center gap-2 font-medium text-base w-[40vw] truncate">
{estimate.name}
{projectDetails?.estimate && projectDetails?.estimate === estimate.id && (
<span className="capitalize px-2 py-0.5 text-xs rounded bg-green-100 text-green-500">
In use
</span>
)}
</h6>
<p className="font-sm text-gray-400 font-normal text-[14px] w-[40vw] truncate">
{estimate.description}
</p>
</div>
<div className="flex items-center gap-8">
<CustomMenu ellipsis>
<CustomMenu.MenuItem onClick={handleActiveEstimate}>
<span className="flex items-center justify-start gap-2">
<SquaresPlusIcon className="h-4 w-4" />
<CustomMenu ellipsis>
{projectDetails?.estimate && projectDetails?.estimate !== estimate.id && (
<CustomMenu.MenuItem onClick={handleUseEstimate}>
<div className="flex items-center justify-start gap-2">
<SquaresPlusIcon className="h-3.5 w-3.5" />
<span>Use estimate</span>
</span>
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setIsEstimatePointsModalOpen(true)}>
<span className="flex items-center justify-start gap-2">
<ListBulletIcon className="h-4 w-4" />
{estimatePoints?.length === 8 ? "Update points" : "Create points"}
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
editEstimate(estimate);
}}
>
<span className="flex items-center justify-start gap-2">
<PencilIcon className="h-4 w-4" />
<span>Edit estimate</span>
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
handleEstimateDelete(estimate.id);
}}
>
<span className="flex items-center justify-start gap-2">
<TrashIcon className="h-4 w-4" />
<span>Delete estimate</span>
</span>
</CustomMenu.MenuItem>
</CustomMenu>
</div>
)}
<CustomMenu.MenuItem onClick={() => setIsEstimatePointsModalOpen(true)}>
<div className="flex items-center justify-start gap-2">
<ListBulletIcon className="h-3.5 w-3.5" />
<span>{estimatePoints?.length === 8 ? "Update points" : "Create points"}</span>
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
editEstimate(estimate);
}}
>
<div className="flex items-center justify-start gap-2">
<PencilIcon className="h-3.5 w-3.5" />
<span>Edit estimate</span>
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
handleEstimateDelete(estimate.id);
}}
>
<div className="flex items-center justify-start gap-2">
<TrashIcon className="h-3.5 w-3.5" />
<span>Delete estimate</span>
</div>
</CustomMenu.MenuItem>
</CustomMenu>
</div>
{estimatePoints && estimatePoints.length > 0 ? (
<div className="flex gap-2">
Expand All @@ -140,11 +153,11 @@ export const SingleEstimate: React.FC<Props> = ({
{estimatePoints.length > 0 && ")"}
</div>
) : (
<div>
<p className= " text-sm text-gray-300">No estimate points</p>
</div>
<div>
<p className=" text-sm text-gray-300">No estimate points</p>
</div>
)}
</div>
</div>
</>
);
};
1 change: 1 addition & 0 deletions apps/app/components/issues/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./comment";
export * from "./sidebar-select";
export * from "./view-select";
export * from "./activity";
export * from "./delete-issue-modal";
export * from "./description-form";
Expand Down
69 changes: 69 additions & 0 deletions apps/app/components/issues/view-select/estimate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from "react";

// ui
import { CustomSelect, Tooltip } from "components/ui";
// icons
import { getPriorityIcon } from "components/icons/priority-icon";
// types
import { IIssue } from "types";
// constants
import { PRIORITIES } from "constants/project";
// services
import trackEventServices from "services/track-event.service";
import useEstimateOption from "hooks/use-estimate-option";

type Props = {
issue: IIssue;
partialUpdateIssue: (formData: Partial<IIssue>) => void;
position?: "left" | "right";
selfPositioned?: boolean;
isNotAllowed: boolean;
};

export const ViewEstimateSelect: React.FC<Props> = ({
issue,
partialUpdateIssue,
position = "left",
selfPositioned = false,
isNotAllowed,
}) => {
const { isEstimateActive, estimatePoints, estimateValue } = useEstimateOption(
issue.estimate_point
);

return (
<CustomSelect
value={issue.priority}
onChange={(data: string) => {
partialUpdateIssue({ priority: data, state: issue.state, target_date: issue.target_date });
trackEventServices.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug: issue.workspace_detail.slug,
workspaceId: issue.workspace_detail.id,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_PRIORITY"
);
}}
label={
<Tooltip tooltipHeading="Estimate" tooltipContent={estimateValue}>
<>{estimateValue}</>
</Tooltip>
}
maxHeight="md"
noChevron
disabled={isNotAllowed}
position={position}
selfPositioned={selfPositioned}
>
{estimatePoints?.map((estimate) => (
<CustomSelect.Option key={estimate.id} value={estimate.key} className="capitalize">
<>{estimate.value}</>
</CustomSelect.Option>
))}
</CustomSelect>
);
};
1 change: 1 addition & 0 deletions apps/app/components/issues/view-select/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./assignee";
export * from "./due-date";
export * from "./estimate";
export * from "./priority";
export * from "./state";
13 changes: 2 additions & 11 deletions apps/app/contexts/user.context.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React, { createContext, ReactElement } from "react";
// next
import { useRouter } from "next/router";
// swr

import useSWR, { KeyedMutator } from "swr";

// services
import userService from "services/user.service";
// constants
import { CURRENT_USER } from "constants/fetch-keys";

// types
import type { IUser } from "types";

Expand All @@ -22,18 +20,11 @@ interface IUserContextProps {
export const UserContext = createContext<IUserContextProps>({} as IUserContextProps);

export const UserProvider = ({ children }: { children: ReactElement }) => {
const router = useRouter();

// API to fetch user information
const { data, error, mutate } = useSWR<IUser>(CURRENT_USER, () => userService.currentUser(), {
shouldRetryOnError: false,
});

if (error) {
router.push("/signin");
return null;
}

return (
<UserContext.Provider
value={{
Expand Down
Loading