[WEB-1846] chore: integrated project other features enabled/disabled feature on project settings and updated the pro icon as a component (#5071)

* chore: integrated time traking enabled/disabled feature on project settings and updated the pro icon as a component

* chore: Showing the toggle and disabled to make any operations on project features

* chore: default exports in constants

* chore: seperated isEnabled and isPro

* chore: updated time traking key

* chore: updated UI in project feature settings
This commit is contained in:
guru_sainath 2024-07-15 19:48:27 +05:30 committed by GitHub
parent 08d9e95a86
commit f5f3c4915f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 183 additions and 83 deletions

View file

@ -4,4 +4,5 @@ export * from "./latest-feature-block";
export * from "./breadcrumb-link";
export * from "./logo-spinner";
export * from "./logo";
export * from "./pro-icon";
export * from "./count-chip";

View file

@ -0,0 +1,16 @@
"use client";
import { FC } from "react";
import { Crown } from "lucide-react";
// helpers
import { cn } from "@/helpers/common.helper";
type TProIcon = {
className?: string;
};
export const ProIcon: FC<TProIcon> = (props) => {
const { className } = props;
return <Crown className={cn("inline-block h-3.5 w-3.5 text-amber-400", className)} />;
};

View file

@ -1,10 +1,11 @@
"use client";
import { FC } from "react";
import { Crown, Info } from "lucide-react";
import { Info } from "lucide-react";
import { TEstimateSystemKeys } from "@plane/types";
import { Tooltip } from "@plane/ui";
// components
import { ProIcon } from "@/components/common";
import { RadioInput } from "@/components/estimates";
// plane web constants
import { ESTIMATE_SYSTEMS } from "@/plane-web/constants/estimates";
@ -39,7 +40,7 @@ export const EstimateCreateStageOne: FC<TEstimateCreateStageOne> = (props) => {
<div className="relative flex items-center gap-2 cursor-no-drop text-custom-text-300">
{ESTIMATE_SYSTEMS[currentSystem]?.name}
<Tooltip tooltipContent={"upgrade"}>
<Crown size={12} className="text-amber-400" />
<ProIcon className="w-3 h-3" />
</Tooltip>
</div>
) : (

View file

@ -2,13 +2,14 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { FileText, Inbox } from "lucide-react";
// types
import { IProject } from "@plane/types";
// ui
import { ContrastIcon, DiceIcon, PhotoFilterIcon, ToggleSwitch, setPromiseToast } from "@plane/ui";
import { ToggleSwitch, Tooltip, setPromiseToast } from "@plane/ui";
// hooks
import { useEventTracker, useProject, useUser } from "@/hooks/store";
// plane web components
import { UpgradeBadge } from "@/plane-web/components/workspace";
// plane web constants
import { PROJECT_FEATURES_LIST } from "@/plane-web/constants/project/settings";
type Props = {
workspaceSlug: string;
@ -16,39 +17,6 @@ type Props = {
isAdmin: boolean;
};
const PROJECT_FEATURES_LIST = [
{
title: "Cycles",
description: "Time-box issues and boost momentum, similar to sprints in scrum.",
icon: <ContrastIcon className="h-4 w-4 flex-shrink-0 rotate-180 text-purple-500" />,
property: "cycle_view",
},
{
title: "Modules",
description: "Group multiple issues together and track the progress.",
icon: <DiceIcon width={16} height={16} className="flex-shrink-0 text-red-500" />,
property: "module_view",
},
{
title: "Views",
description: "Apply filters to issues and save them to analyse and investigate work.",
icon: <PhotoFilterIcon className="h-4 w-4 flex-shrink-0 text-cyan-500" />,
property: "issue_views_view",
},
{
title: "Pages",
description: "Document ideas, feature requirements, discussions within your project.",
icon: <FileText className="h-4 w-4 flex-shrink-0 text-red-400" />,
property: "page_view",
},
{
title: "Inbox",
description: "Capture external inputs, move valid issues to workflow.",
icon: <Inbox className="h-4 w-4 flex-shrink-0 text-fuchsia-500" />,
property: "inbox_view",
},
];
export const ProjectFeaturesList: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, isAdmin } = props;
// store hooks
@ -58,9 +26,20 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
// derived values
const currentProjectDetails = getProjectById(projectId);
const handleSubmit = async (formData: Partial<IProject>) => {
const handleSubmit = async (featureKey: string, featureProperty: string) => {
if (!workspaceSlug || !projectId || !currentProjectDetails) return;
const updateProjectPromise = updateProject(workspaceSlug, projectId, formData);
// capturing event
captureEvent(`Toggle ${featureKey}`, {
enabled: !currentProjectDetails?.[featureProperty as keyof IProject],
element: "Project settings feature page",
});
// making the request to update the project feature
const settingsPayload = {
[featureProperty]: !currentProjectDetails?.[featureProperty as keyof IProject],
};
const updateProjectPromise = updateProject(workspaceSlug, projectId, settingsPayload);
setPromiseToast(updateProjectPromise, {
loading: "Updating project feature...",
success: {
@ -77,35 +56,50 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
if (!currentUser) return <></>;
return (
<div className="mx-4">
{PROJECT_FEATURES_LIST.map((feature) => (
<div
key={feature.property}
className="flex items-center justify-between gap-x-8 gap-y-2 border-b border-custom-border-100 bg-custom-background-100 pb-2 pt-4 last:border-b-0"
>
<div className="flex items-start gap-3">
<div className="flex items-center justify-center rounded bg-custom-primary-50/10 p-3">{feature.icon}</div>
<div className="">
<h4 className="text-sm font-medium leading-5">{feature.title}</h4>
<p className="text-sm leading-5 tracking-tight text-custom-text-300">{feature.description}</p>
<div className="mx-4 space-y-6">
{Object.keys(PROJECT_FEATURES_LIST).map((featureSectionKey) => {
const feature = PROJECT_FEATURES_LIST[featureSectionKey];
return (
<div key={featureSectionKey} className="">
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">{feature.title}</h3>
</div>
{Object.keys(feature.featureList).map((featureItemKey) => {
const featureItem = feature.featureList[featureItemKey];
return (
<div
key={featureItemKey}
className="flex items-center justify-between gap-x-8 gap-y-2 border-b border-custom-border-100 bg-custom-background-100 pb-2 pt-4 last:border-b-0"
>
<div className="flex items-start gap-3">
<div className="flex items-center justify-center rounded bg-custom-background-90 p-3">
{featureItem.icon}
</div>
<div>
<div className="flex items-center gap-2">
<h4 className="text-sm font-medium leading-5">{featureItem.title}</h4>
{featureItem.isPro && (
<Tooltip tooltipContent="Pro feature" position="top">
<UpgradeBadge />
</Tooltip>
)}
</div>
<p className="text-sm leading-5 tracking-tight text-custom-text-300">{featureItem.description}</p>
</div>
</div>
<ToggleSwitch
value={Boolean(currentProjectDetails?.[featureItem.property as keyof IProject])}
onChange={() => handleSubmit(featureItemKey, featureItem.property)}
disabled={!featureItem.isEnabled || !isAdmin}
size="sm"
/>
</div>
);
})}
</div>
<ToggleSwitch
value={Boolean(currentProjectDetails?.[feature.property as keyof IProject])}
onChange={() => {
captureEvent(`Toggle ${feature.title.toLowerCase()}`, {
enabled: !currentProjectDetails?.[feature.property as keyof IProject],
element: "Project settings feature page",
});
handleSubmit({
[feature.property]: !currentProjectDetails?.[feature.property as keyof IProject],
});
}}
disabled={!isAdmin}
size="sm"
/>
</div>
))}
);
})}
</div>
);
});