Files
notesnook/apps/web/src/components/dialogs/feature-dialog.tsx

218 lines
6.4 KiB
TypeScript
Raw Normal View History

/*
This file is part of the Notesnook project (https://notesnook.com/)
2022-08-30 16:13:11 +05:00
2023-01-16 13:44:52 +05:00
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Text, Flex } from "@theme-ui/components";
2022-03-17 12:31:06 +05:00
import Dialog from "./dialog";
import { getHomeRoute, hardNavigate } from "../../navigation";
import { appVersion } from "../../utils/version";
import Config from "../../utils/config";
2023-01-30 13:44:29 +05:00
import { isDesktop, isTesting } from "../../utils/platform";
2022-07-02 11:33:10 +05:00
import { useEffect } from "react";
2023-01-30 13:44:29 +05:00
import { ArrowRight, Checkmark, Icon, Warn } from "../icons";
2022-03-17 12:31:06 +05:00
type CallToAction = {
title: string;
icon?: Icon;
2022-03-17 12:31:06 +05:00
action?: () => void;
};
type SubFeature = {
title: string;
icon?: Icon;
2022-03-17 12:31:06 +05:00
subtitle?: string | JSX.Element;
};
type Feature = {
shouldShow?: () => boolean;
title: string;
subtitle?: string;
cta: CallToAction;
subFeatures?: SubFeature[];
};
export type FeatureKeys = "confirmed" | "highlights";
2022-03-17 12:31:06 +05:00
const features: Record<FeatureKeys, Feature> = {
confirmed: {
title: "Email confirmed!",
subtitle: "You can now sync your notes to unlimited devices.",
cta: {
title: "Continue",
icon: ArrowRight,
action: () => hardNavigate(getHomeRoute())
}
2022-03-17 12:31:06 +05:00
},
highlights: {
2022-07-04 14:51:47 +05:00
title: appVersion.isBeta
? "Welcome to Notesnook Beta!"
: "✨ Highlights ✨",
subtitle: appVersion.isBeta
? `v${appVersion.clean}-beta`
: `Welcome to v${appVersion.clean}`,
subFeatures: appVersion.isBeta
? [
{
icon: Warn,
2022-07-04 14:51:47 +05:00
title: "Notice",
subtitle: (
<>
This is the beta version and as such will contain bugs. Things
are expected to break but should be generally stable. Please use
the <Code text="Report an issue" /> button to report all bugs.
Thank you!
</>
)
2022-07-04 14:51:47 +05:00
},
{
icon: Warn,
2022-07-04 14:51:47 +05:00
title: "Notice 2",
subtitle: (
<>
Switching between beta &amp; stable versions can cause weird
issues including data loss. It is recommended that you do not
use both simultaneously. You can switch once the beta version
enters stable.
</>
)
}
2022-07-04 14:51:47 +05:00
]
2023-01-30 13:44:29 +05:00
: isDesktop()
? [
2022-11-23 17:23:03 +05:00
{
2023-01-30 13:44:29 +05:00
title: "Multi-language spell check",
2022-11-23 17:23:03 +05:00
subtitle:
2023-01-30 13:44:29 +05:00
"Spell checking support is finally here. You can enable/disable & add new languages support from settings. The spell checker supports multiple languages at once so feel free to add as many as you'd like."
2022-11-23 17:23:03 +05:00
},
{
2023-01-30 13:44:29 +05:00
title: "Better OS integration",
2022-11-23 17:23:03 +05:00
subtitle:
2023-01-30 13:44:29 +05:00
"Notesnook now supports all the standard desktop integration features like auto start on startup, minimize to system tray, shortcuts from jumplist, dock menu etc. There are some other goodies as well like native notifications for reminders."
2023-01-14 13:17:01 +05:00
}
2023-01-30 13:44:29 +05:00
]
: [],
2022-03-17 12:31:06 +05:00
cta: {
title: "Got it",
icon: Checkmark,
2022-03-17 12:31:06 +05:00
action: () => {
Config.set(`${appVersion.numerical}:highlights`, true);
}
2022-03-17 12:31:06 +05:00
},
shouldShow: () => {
2022-06-08 13:21:34 +05:00
if (!features.highlights.subFeatures?.length) return false;
const key = `${appVersion.numerical}:highlights`;
const hasShownBefore = Config.get(key, false) as boolean;
2022-07-04 14:51:47 +05:00
const hasShownAny =
appVersion.isBeta || Config.has((k) => k.endsWith(":highlights"));
if (!hasShownAny) Config.set(key, true);
2022-06-08 13:21:34 +05:00
return hasShownAny && !isTesting() && !hasShownBefore;
}
}
2022-03-17 12:31:06 +05:00
};
type FeatureDialogProps = {
featureName: FeatureKeys;
onClose: (result: boolean) => void;
};
function FeatureDialog(props: FeatureDialogProps) {
2022-07-02 11:33:10 +05:00
const { featureName, onClose } = props;
2022-03-17 12:31:06 +05:00
const feature = features[featureName];
2022-07-02 11:33:10 +05:00
useEffect(() => {
if (!feature || (feature.shouldShow && !feature.shouldShow())) {
onClose(false);
}
}, [feature, onClose]);
2022-03-17 12:31:06 +05:00
return (
<Dialog
isOpen={true}
title={feature.title}
description={feature.subtitle}
alignment="center"
positiveButton={{
text: (
<Flex>
{feature.cta.icon && (
<feature.cta.icon color="primary" size={16} sx={{ mr: 1 }} />
)}
{feature.cta.title}
</Flex>
),
onClick: () => {
if (feature.cta.action) feature.cta.action();
props.onClose(true);
}
2022-03-17 12:31:06 +05:00
}}
>
<Flex mt={2} sx={{ flexDirection: "column", overflowY: "auto" }}>
2022-03-17 12:31:06 +05:00
{feature.subFeatures?.map((feature) => (
<Flex
2022-08-30 16:13:11 +05:00
key={feature.title}
2022-03-17 12:31:06 +05:00
mb={2}
bg="bgSecondary"
p={2}
sx={{
borderRadius: "default",
":hover": { bg: "hover" },
flexDirection: "column"
}}
2022-03-17 12:31:06 +05:00
>
<Flex sx={{ alignItems: "center", justifyContent: "start" }}>
2022-03-17 12:31:06 +05:00
{feature.icon && <feature.icon size={14} color="primary" />}
<Text variant="subtitle" ml={1} sx={{ fontWeight: "normal" }}>
2022-03-17 12:31:06 +05:00
{feature.title}
</Text>
</Flex>
{feature.subtitle && (
<Text variant="body" sx={{ color: "icon" }}>
2022-03-17 12:31:06 +05:00
{feature.subtitle}
</Text>
)}
</Flex>
))}
</Flex>
</Dialog>
);
}
export default FeatureDialog;
type CodeProps = { text: string; href?: string };
export function Code(props: CodeProps) {
return (
<Text
as="code"
sx={{
bg: "background",
color: "text",
px: 1,
borderRadius: 5,
fontFamily: "monospace",
fontSize: "subBody",
border: "1px solid var(--border)",
cursor: props.href ? "pointer" : "unset"
2022-03-17 12:31:06 +05:00
}}
onClick={() => {
if (props.href) window.open(props.href, "_target");
}}
>
{props.text}
</Text>
);
}