forked from github/plane
chore: reove unused files (#2567)
This commit is contained in:
parent
8072bbb559
commit
98716859d5
@ -1,175 +0,0 @@
|
||||
import React from "react";
|
||||
// headless ui
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// lucide icons
|
||||
import { ChevronDown, Search, X, Check } from "lucide-react";
|
||||
// hooks
|
||||
import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown";
|
||||
|
||||
interface IFiltersOption {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface IIssuePropertyState {
|
||||
options: IFiltersOption[];
|
||||
value?: any;
|
||||
onChange?: (id: any, data: IFiltersOption) => void;
|
||||
disabled?: boolean;
|
||||
|
||||
className?: string;
|
||||
buttonClassName?: string;
|
||||
optionsClassName?: string;
|
||||
dropdownArrow?: boolean;
|
||||
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export const IssuePropertyState: React.FC<IIssuePropertyState> = ({
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
disabled,
|
||||
|
||||
className,
|
||||
buttonClassName,
|
||||
optionsClassName,
|
||||
dropdownArrow = true,
|
||||
|
||||
children,
|
||||
}) => {
|
||||
const dropdownBtn = React.useRef<any>(null);
|
||||
const dropdownOptions = React.useRef<any>(null);
|
||||
|
||||
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions);
|
||||
|
||||
const selectedOption: IFiltersOption | null | undefined =
|
||||
(value && options.find((person: IFiltersOption) => person.id === value)) || null;
|
||||
|
||||
const filteredOptions: IFiltersOption[] =
|
||||
search === ""
|
||||
? options && options.length > 0
|
||||
? options
|
||||
: []
|
||||
: options && options.length > 0
|
||||
? options.filter((person: IFiltersOption) =>
|
||||
person.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, ""))
|
||||
)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
className={`${className}`}
|
||||
value={selectedOption && selectedOption.id}
|
||||
onChange={(data: string) => {
|
||||
if (onChange && selectedOption) onChange(data, selectedOption);
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
{({ open }: { open: boolean }) => {
|
||||
if (open) {
|
||||
if (!isOpen) setIsOpen(true);
|
||||
} else if (isOpen) setIsOpen(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Combobox.Button
|
||||
ref={dropdownBtn}
|
||||
type="button"
|
||||
className={`flex items-center justify-between gap-1 w-full px-1 py-1 rounded-sm shadow-sm border border-custom-border-300 duration-300 outline-none ${
|
||||
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
||||
} ${buttonClassName}`}
|
||||
>
|
||||
{children ? (
|
||||
children
|
||||
) : (
|
||||
<div className="text-xs">{(selectedOption && selectedOption?.title) || "Select option"}</div>
|
||||
)}
|
||||
|
||||
{dropdownArrow && !disabled && (
|
||||
<div className="flex-shrink-0 w-[14px] h-[14px] flex justify-center items-center">
|
||||
<ChevronDown width={14} strokeWidth={2} />
|
||||
</div>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
|
||||
{options && options.length > 0 ? (
|
||||
<div className={`${open ? "fixed z-20 top-0 left-0 h-full w-full cursor-auto" : ""}`}>
|
||||
<Combobox.Options
|
||||
ref={dropdownOptions}
|
||||
className={`absolute z-10 border border-custom-border-300 p-2 rounded bg-custom-background-100 text-xs shadow-lg focus:outline-none min-w-48 max-w-60 whitespace-nowrap mt-1 space-y-1 ${optionsClassName}`}
|
||||
>
|
||||
<div className="flex w-full items-center justify-start rounded border border-custom-border-200 bg-custom-background-90 px-1">
|
||||
<div className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm">
|
||||
<Search width={12} strokeWidth={2} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Combobox.Input
|
||||
className="w-full bg-transparent p-1 text-xs text-custom-text-200 placeholder:text-custom-text-400 focus:outline-none"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder="Search"
|
||||
displayValue={(assigned: any) => assigned?.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{search && search.length > 0 && (
|
||||
<div
|
||||
onClick={() => setSearch("")}
|
||||
className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80"
|
||||
>
|
||||
<X width={12} strokeWidth={2} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={`space-y-0.5 max-h-48 overflow-y-scroll`}>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
filteredOptions.map((option) => (
|
||||
<Combobox.Option
|
||||
key={option.id}
|
||||
value={option.id}
|
||||
className={({ active, selected }) =>
|
||||
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
|
||||
active || selected ? "bg-custom-background-80" : ""
|
||||
} ${selected ? "text-custom-text-100" : "text-custom-text-200"}`
|
||||
}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<div className="flex justify-between items-center gap-1 w-full px-1">
|
||||
<div className="line-clamp-1">{option.title}</div>
|
||||
{selected && (
|
||||
<div className="flex-shrink-0 w-[13px] h-[13px] flex justify-center items-center">
|
||||
<Check width={13} strokeWidth={2} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Combobox.Option>
|
||||
))
|
||||
) : (
|
||||
<span className="flex items-center gap-2 p-1">
|
||||
<p className="text-left text-custom-text-200 ">No matching results</p>
|
||||
</span>
|
||||
)
|
||||
) : (
|
||||
<p className="text-center text-custom-text-200">Loading...</p>
|
||||
)}
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-center text-custom-text-200">No options available.</p>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Combobox>
|
||||
);
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
// components
|
||||
import { LabelSelect } from "components/project";
|
||||
import { LabelSelect } from "components/labels";
|
||||
// types
|
||||
import { IIssueLabels } from "types";
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
// components
|
||||
import { LabelSelect } from "components/project";
|
||||
import { LabelSelect } from "components/labels";
|
||||
// hooks
|
||||
import useSubIssue from "hooks/use-sub-issue";
|
||||
// types
|
||||
|
@ -1,117 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
// services
|
||||
import { TrackEventService } from "services/track_event.service";
|
||||
// ui
|
||||
import { AssigneesList, Avatar } from "components/ui";
|
||||
import { CustomSearchSelect, Tooltip } from "@plane/ui";
|
||||
import { User2 } from "lucide-react";
|
||||
// types
|
||||
import { IUser, IIssue } from "types";
|
||||
// hooks
|
||||
import useProjectMembers from "hooks/use-project-members";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
partialUpdateIssue: (formData: Partial<IIssue>, issue: IIssue) => void;
|
||||
position?: "left" | "right";
|
||||
tooltipPosition?: "top" | "bottom";
|
||||
selfPositioned?: boolean;
|
||||
customButton?: boolean;
|
||||
user: IUser | undefined;
|
||||
isNotAllowed: boolean;
|
||||
};
|
||||
|
||||
const trackEventService = new TrackEventService();
|
||||
|
||||
export const ViewAssigneeSelect: React.FC<Props> = ({
|
||||
issue,
|
||||
partialUpdateIssue,
|
||||
// position = "left",
|
||||
// selfPositioned = false,
|
||||
tooltipPosition = "top",
|
||||
user,
|
||||
isNotAllowed,
|
||||
customButton = false,
|
||||
}) => {
|
||||
const [fetchAssignees, setFetchAssignees] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { members } = useProjectMembers(workspaceSlug?.toString(), issue.project, fetchAssignees);
|
||||
|
||||
const options = members?.map((member: any) => ({
|
||||
value: member.member.id,
|
||||
query: member.member.display_name,
|
||||
content: (
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar user={member.member} />
|
||||
{member.member.display_name}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
const assigneeLabel = (
|
||||
<Tooltip
|
||||
position={tooltipPosition}
|
||||
tooltipHeading="Assignees"
|
||||
tooltipContent={
|
||||
issue.assignee_details.length > 0
|
||||
? issue.assignee_details.map((assignee) => assignee?.display_name).join(", ")
|
||||
: "No Assignee"
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={`flex ${
|
||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"
|
||||
} items-center gap-2 text-custom-text-200`}
|
||||
>
|
||||
{issue.assignees && issue.assignees.length > 0 && Array.isArray(issue.assignees) ? (
|
||||
<div className="-my-0.5 flex items-center justify-center gap-2">
|
||||
<AssigneesList userIds={issue.assignees} length={3} showLength={true} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center gap-2 px-1.5 py-1 rounded shadow-sm border border-custom-border-300">
|
||||
<User2 className="h-4 w-4" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
return (
|
||||
<CustomSearchSelect
|
||||
value={issue.assignees}
|
||||
buttonClassName="!p-0"
|
||||
onChange={(data: any) => {
|
||||
const newData = issue.assignees ?? [];
|
||||
|
||||
if (newData.includes(data)) newData.splice(newData.indexOf(data), 1);
|
||||
else newData.push(data);
|
||||
|
||||
partialUpdateIssue({ assignees: data }, issue);
|
||||
|
||||
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
||||
{
|
||||
workspaceSlug,
|
||||
workspaceId: issue.workspace,
|
||||
projectId: issue.project_detail.id,
|
||||
projectIdentifier: issue.project_detail.identifier,
|
||||
projectName: issue.project_detail.name,
|
||||
issueId: issue.id,
|
||||
},
|
||||
"ISSUE_PROPERTY_UPDATE_ASSIGNEE",
|
||||
user as IUser
|
||||
);
|
||||
}}
|
||||
options={options}
|
||||
{...(customButton ? { customButton: assigneeLabel } : { label: assigneeLabel })}
|
||||
multiple
|
||||
noChevron
|
||||
disabled={isNotAllowed}
|
||||
onOpen={() => setFetchAssignees(true)}
|
||||
width="w-full min-w-[12rem]"
|
||||
/>
|
||||
);
|
||||
};
|
@ -1,6 +1,3 @@
|
||||
export * from "./assignee";
|
||||
export * from "./due-date";
|
||||
export * from "./estimate";
|
||||
export * from "./label";
|
||||
export * from "./priority";
|
||||
export * from "./start-date";
|
||||
export * from "./start-date";
|
||||
|
@ -1,154 +0,0 @@
|
||||
import { useState, FC } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// services
|
||||
import { IssueLabelService } from "services/issue";
|
||||
// component
|
||||
import { CreateLabelModal } from "components/labels";
|
||||
// ui
|
||||
import { CustomSearchSelect, Tooltip } from "@plane/ui";
|
||||
// icons
|
||||
import { Plus, Tag } from "lucide-react";
|
||||
// types
|
||||
import { IUser, IIssue, IIssueLabels } from "types";
|
||||
// fetch-keys
|
||||
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
partialUpdateIssue: (formData: Partial<IIssue>, issue: IIssue) => void;
|
||||
position?: "left" | "right";
|
||||
selfPositioned?: boolean;
|
||||
tooltipPosition?: "top" | "bottom";
|
||||
customButton?: boolean;
|
||||
user: IUser | undefined;
|
||||
isNotAllowed: boolean;
|
||||
};
|
||||
|
||||
const issueLabelStore = new IssueLabelService();
|
||||
|
||||
export const ViewLabelSelect: FC<Props> = ({
|
||||
issue,
|
||||
partialUpdateIssue,
|
||||
// position = "left",
|
||||
// selfPositioned = false,
|
||||
tooltipPosition = "top",
|
||||
user,
|
||||
isNotAllowed,
|
||||
customButton = false,
|
||||
}) => {
|
||||
const [labelModal, setLabelModal] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
||||
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => issueLabelStore.getProjectIssueLabels(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
const options = issueLabels?.map((label) => ({
|
||||
value: label.id,
|
||||
query: label.name,
|
||||
content: (
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<span
|
||||
className="h-2.5 w-2.5 flex-shrink-0 rounded-full"
|
||||
style={{
|
||||
backgroundColor: label.color,
|
||||
}}
|
||||
/>
|
||||
<span>{label.name}</span>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
const labelsLabel = (
|
||||
<Tooltip
|
||||
position={tooltipPosition}
|
||||
tooltipHeading="Labels"
|
||||
tooltipContent={
|
||||
issue.labels.length > 0
|
||||
? issue.labels
|
||||
.map((labelId) => {
|
||||
const label = issueLabels?.find((l) => l.id === labelId);
|
||||
|
||||
return label?.name ?? "";
|
||||
})
|
||||
.join(", ")
|
||||
: "No label"
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={`flex ${
|
||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"
|
||||
} items-center gap-2 text-custom-text-200`}
|
||||
>
|
||||
{issue.labels.length > 0 ? (
|
||||
<>
|
||||
{issue.labels.slice(0, 4).map((labelId, index) => {
|
||||
const label = issueLabels?.find((l) => l.id === labelId);
|
||||
|
||||
return (
|
||||
<div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}>
|
||||
<span
|
||||
className={`h-4 w-4 flex-shrink-0 rounded-full border group-hover:bg-custom-background-80 border-custom-border-200`}
|
||||
style={{
|
||||
backgroundColor: label?.color ?? "#000000",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{issue.labels.length > 4 ? <span>+{issue.labels.length - 4}</span> : null}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Tag className="h-3.5 w-3.5 text-custom-text-200" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
const footerOption = (
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full select-none items-center rounded py-2 px-1 hover:bg-custom-background-80"
|
||||
onClick={() => setLabelModal(true)}
|
||||
>
|
||||
<span className="flex items-center justify-start gap-1 text-custom-text-200">
|
||||
<Plus className="h-4 w-4" aria-hidden="true" />
|
||||
<span>Create New Label</span>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{projectId && (
|
||||
<CreateLabelModal
|
||||
isOpen={labelModal}
|
||||
handleClose={() => setLabelModal(false)}
|
||||
projectId={projectId.toString()}
|
||||
user={user}
|
||||
/>
|
||||
)}
|
||||
<CustomSearchSelect
|
||||
value={issue.labels}
|
||||
onChange={(data: string[]) => {
|
||||
partialUpdateIssue({ labels: data }, issue);
|
||||
}}
|
||||
options={options}
|
||||
{...(customButton ? { customButton: labelsLabel } : { label: labelsLabel })}
|
||||
multiple
|
||||
noChevron
|
||||
disabled={isNotAllowed}
|
||||
footerOption={footerOption}
|
||||
width="w-full min-w-[12rem]"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,106 +0,0 @@
|
||||
import React from "react";
|
||||
import { useRouter } from "next/router";
|
||||
// services
|
||||
import { TrackEventService } from "services/track_event.service";
|
||||
// ui
|
||||
import { CustomSelect, Tooltip, PriorityIcon } from "@plane/ui";
|
||||
// helpers
|
||||
import { capitalizeFirstLetter } from "helpers/string.helper";
|
||||
// types
|
||||
import { IUser, IIssue, TIssuePriorities } from "types";
|
||||
// constants
|
||||
import { PRIORITIES } from "constants/project";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
partialUpdateIssue: (formData: Partial<IIssue>, issue: IIssue) => void;
|
||||
position?: "left" | "right";
|
||||
tooltipPosition?: "top" | "bottom";
|
||||
selfPositioned?: boolean;
|
||||
noBorder?: boolean;
|
||||
user: IUser | undefined;
|
||||
isNotAllowed: boolean;
|
||||
};
|
||||
|
||||
const trackEventService = new TrackEventService();
|
||||
|
||||
export const ViewPrioritySelect: React.FC<Props> = ({
|
||||
issue,
|
||||
partialUpdateIssue,
|
||||
// position = "left",
|
||||
tooltipPosition = "top",
|
||||
// selfPositioned = false,
|
||||
noBorder = false,
|
||||
user,
|
||||
isNotAllowed,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
return (
|
||||
<CustomSelect
|
||||
value={issue.priority}
|
||||
onChange={(data: TIssuePriorities) => {
|
||||
partialUpdateIssue({ priority: data }, issue);
|
||||
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
||||
{
|
||||
workspaceSlug,
|
||||
workspaceId: issue.workspace,
|
||||
projectId: issue.project_detail.id,
|
||||
projectIdentifier: issue.project_detail.identifier,
|
||||
projectName: issue.project_detail.name,
|
||||
issueId: issue.id,
|
||||
},
|
||||
"ISSUE_PROPERTY_UPDATE_PRIORITY",
|
||||
user as IUser
|
||||
);
|
||||
}}
|
||||
maxHeight="md"
|
||||
customButton={
|
||||
<button
|
||||
type="button"
|
||||
className={`grid place-items-center rounded ${isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"} ${
|
||||
noBorder ? "" : "h-6 w-6 border shadow-sm"
|
||||
} ${
|
||||
noBorder
|
||||
? ""
|
||||
: issue.priority === "urgent"
|
||||
? "border-red-500/20 bg-red-500"
|
||||
: "border-custom-border-300 bg-custom-background-100"
|
||||
} items-center`}
|
||||
>
|
||||
<Tooltip tooltipHeading="Priority" tooltipContent={issue.priority ?? "None"} position={tooltipPosition}>
|
||||
<span className="flex gap-1 items-center text-custom-text-200 text-xs">
|
||||
<PriorityIcon
|
||||
priority={issue.priority}
|
||||
className={`h-3.5 w-3.5 ${
|
||||
issue.priority === "urgent"
|
||||
? "text-white"
|
||||
: issue.priority === "high"
|
||||
? "text-orange-500"
|
||||
: issue.priority === "medium"
|
||||
? "text-yellow-500"
|
||||
: issue.priority === "low"
|
||||
? "text-green-500"
|
||||
: "text-custom-text-200"
|
||||
}`}
|
||||
/>
|
||||
{noBorder ? capitalizeFirstLetter(issue.priority ?? "None") : ""}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</button>
|
||||
}
|
||||
noChevron
|
||||
disabled={isNotAllowed}
|
||||
>
|
||||
{PRIORITIES?.map((priority) => (
|
||||
<CustomSelect.Option key={priority} value={priority} className="capitalize">
|
||||
<>
|
||||
<PriorityIcon priority={priority} className="h-3.5 w-3.5" />
|
||||
{priority ?? "None"}
|
||||
</>
|
||||
</CustomSelect.Option>
|
||||
))}
|
||||
</CustomSelect>
|
||||
);
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
export * from "./create-label-modal";
|
||||
export * from "./create-update-label-inline";
|
||||
export * from "./delete-label-modal";
|
||||
export * from "./label-select";
|
||||
export * from "./labels-list-modal";
|
||||
export * from "./single-label-group";
|
||||
export * from "./single-label";
|
||||
|
@ -7,7 +7,6 @@ export * from "./delete-project-modal";
|
||||
export * from "./form-loader";
|
||||
export * from "./form";
|
||||
export * from "./join-project-modal";
|
||||
export * from "./label-select";
|
||||
export * from "./leave-project-modal";
|
||||
export * from "./member-select";
|
||||
export * from "./members-select";
|
||||
|
@ -1,122 +0,0 @@
|
||||
import { createContext, useCallback, useReducer, useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
// swr
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import ToastAlert from "components/toast-alert";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
// fetch-keys
|
||||
import { USER_PROJECT_VIEW } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
// constants
|
||||
|
||||
export const themeContext = createContext<ContextType>({} as ContextType);
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
|
||||
type ThemeProps = {
|
||||
collapsed: boolean;
|
||||
};
|
||||
|
||||
type ReducerActionType = {
|
||||
type: "TOGGLE_SIDEBAR" | "REHYDRATE_THEME";
|
||||
payload?: Partial<ThemeProps>;
|
||||
};
|
||||
|
||||
type ContextType = {
|
||||
collapsed: boolean;
|
||||
toggleCollapsed: () => void;
|
||||
};
|
||||
|
||||
type StateType = {
|
||||
collapsed: boolean;
|
||||
};
|
||||
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
||||
|
||||
export const initialState: StateType = {
|
||||
collapsed: false,
|
||||
};
|
||||
|
||||
export const reducer: ReducerFunctionType = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
|
||||
switch (type) {
|
||||
case "TOGGLE_SIDEBAR":
|
||||
const newState = {
|
||||
...state,
|
||||
collapsed: !state.collapsed,
|
||||
};
|
||||
localStorage.setItem("collapsed", JSON.stringify(newState.collapsed));
|
||||
return newState;
|
||||
|
||||
case "REHYDRATE_THEME": {
|
||||
let collapsed: any = localStorage.getItem("collapsed");
|
||||
collapsed = collapsed ? JSON.parse(collapsed) : false;
|
||||
return { ...initialState, ...payload, collapsed };
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ThemeContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const { user } = useUserAuth(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { data: myViewProps } = useSWR(
|
||||
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMemberMe(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
const toggleCollapsed = useCallback(() => {
|
||||
dispatch({
|
||||
type: "TOGGLE_SIDEBAR",
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({
|
||||
type: "REHYDRATE_THEME",
|
||||
payload: myViewProps?.view_props as any,
|
||||
});
|
||||
}, [myViewProps]);
|
||||
|
||||
useEffect(() => {
|
||||
const theme = localStorage.getItem("theme");
|
||||
|
||||
if (theme) {
|
||||
if (theme === "custom") {
|
||||
if (user && user.theme.palette) {
|
||||
applyTheme(
|
||||
user.theme.palette !== ",,,," ? user.theme.palette : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
user.theme.darkPalette
|
||||
);
|
||||
}
|
||||
} else unsetCustomCssVariables();
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
return (
|
||||
<themeContext.Provider
|
||||
value={{
|
||||
collapsed: state.collapsed,
|
||||
toggleCollapsed,
|
||||
}}
|
||||
>
|
||||
<ToastAlert />
|
||||
{children}
|
||||
</themeContext.Provider>
|
||||
);
|
||||
};
|
@ -1,50 +0,0 @@
|
||||
import { FC, ReactElement, createContext } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// types
|
||||
import { IWorkspace } from "types";
|
||||
// constants
|
||||
import { USER_WORKSPACES } from "constants/fetch-keys";
|
||||
|
||||
export interface WorkspaceProviderProps {
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
export interface WorkspaceContextProps {
|
||||
workspaces: IWorkspace[];
|
||||
activeWorkspace: IWorkspace | undefined;
|
||||
mutateWorkspaces: () => void;
|
||||
}
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
export const WorkspaceContext = createContext<WorkspaceContextProps>({} as WorkspaceContextProps);
|
||||
|
||||
export const WorkspaceProvider: FC<WorkspaceProviderProps> = (props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
// API to fetch user information
|
||||
const { data = [], error, mutate } = useSWR<IWorkspace[]>(USER_WORKSPACES, () => workspaceService.userWorkspaces());
|
||||
// active workspace
|
||||
const activeWorkspace = data?.find((w) => w.slug === workspaceSlug);
|
||||
|
||||
return (
|
||||
<WorkspaceContext.Provider
|
||||
value={{
|
||||
workspaces: error ? [] : data,
|
||||
activeWorkspace,
|
||||
mutateWorkspaces: mutate,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WorkspaceContext.Provider>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user