mirror of
https://github.com/chartdb/chartdb.git
synced 2025-10-24 08:33:44 +00:00
add buckle dialog (#498)
This commit is contained in:
BIN
public/buckle-animated.gif
Normal file
BIN
public/buckle-animated.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 404 KiB |
BIN
public/buckle.png
Normal file
BIN
public/buckle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -40,6 +40,10 @@ export interface DialogContext {
|
|||||||
openStarUsDialog: () => void;
|
openStarUsDialog: () => void;
|
||||||
closeStarUsDialog: () => void;
|
closeStarUsDialog: () => void;
|
||||||
|
|
||||||
|
// Buckle dialog
|
||||||
|
openBuckleDialog: () => void;
|
||||||
|
closeBuckleDialog: () => void;
|
||||||
|
|
||||||
// Export image dialog
|
// Export image dialog
|
||||||
openExportImageDialog: (
|
openExportImageDialog: (
|
||||||
params: Omit<ExportImageDialogProps, 'dialog'>
|
params: Omit<ExportImageDialogProps, 'dialog'>
|
||||||
@@ -80,4 +84,6 @@ export const dialogContext = createContext<DialogContext>({
|
|||||||
closeExportDiagramDialog: emptyFn,
|
closeExportDiagramDialog: emptyFn,
|
||||||
openImportDiagramDialog: emptyFn,
|
openImportDiagramDialog: emptyFn,
|
||||||
closeImportDiagramDialog: emptyFn,
|
closeImportDiagramDialog: emptyFn,
|
||||||
|
openBuckleDialog: emptyFn,
|
||||||
|
closeBuckleDialog: emptyFn,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import type { ExportImageDialogProps } from '@/dialogs/export-image-dialog/expor
|
|||||||
import { ExportImageDialog } from '@/dialogs/export-image-dialog/export-image-dialog';
|
import { ExportImageDialog } from '@/dialogs/export-image-dialog/export-image-dialog';
|
||||||
import { ExportDiagramDialog } from '@/dialogs/export-diagram-dialog/export-diagram-dialog';
|
import { ExportDiagramDialog } from '@/dialogs/export-diagram-dialog/export-diagram-dialog';
|
||||||
import { ImportDiagramDialog } from '@/dialogs/import-diagram-dialog/import-diagram-dialog';
|
import { ImportDiagramDialog } from '@/dialogs/import-diagram-dialog/import-diagram-dialog';
|
||||||
|
import { BuckleDialog } from '@/dialogs/buckle-dialog/buckle-dialog';
|
||||||
|
|
||||||
export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||||
children,
|
children,
|
||||||
@@ -27,6 +28,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
const [openCreateRelationshipDialog, setOpenCreateRelationshipDialog] =
|
const [openCreateRelationshipDialog, setOpenCreateRelationshipDialog] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [openStarUsDialog, setOpenStarUsDialog] = useState(false);
|
const [openStarUsDialog, setOpenStarUsDialog] = useState(false);
|
||||||
|
const [openBuckleDialog, setOpenBuckleDialog] = useState(false);
|
||||||
|
|
||||||
// Export image dialog
|
// Export image dialog
|
||||||
const [openExportImageDialog, setOpenExportImageDialog] = useState(false);
|
const [openExportImageDialog, setOpenExportImageDialog] = useState(false);
|
||||||
@@ -114,6 +116,8 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
closeTableSchemaDialog: () => setOpenTableSchemaDialog(false),
|
closeTableSchemaDialog: () => setOpenTableSchemaDialog(false),
|
||||||
openStarUsDialog: () => setOpenStarUsDialog(true),
|
openStarUsDialog: () => setOpenStarUsDialog(true),
|
||||||
closeStarUsDialog: () => setOpenStarUsDialog(false),
|
closeStarUsDialog: () => setOpenStarUsDialog(false),
|
||||||
|
closeBuckleDialog: () => setOpenBuckleDialog(false),
|
||||||
|
openBuckleDialog: () => setOpenBuckleDialog(true),
|
||||||
closeExportImageDialog: () => setOpenExportImageDialog(false),
|
closeExportImageDialog: () => setOpenExportImageDialog(false),
|
||||||
openExportImageDialog: openExportImageDialogHandler,
|
openExportImageDialog: openExportImageDialogHandler,
|
||||||
openExportDiagramDialog: () => setOpenExportDiagramDialog(true),
|
openExportDiagramDialog: () => setOpenExportDiagramDialog(true),
|
||||||
@@ -149,6 +153,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
/>
|
/>
|
||||||
<ExportDiagramDialog dialog={{ open: openExportDiagramDialog }} />
|
<ExportDiagramDialog dialog={{ open: openExportDiagramDialog }} />
|
||||||
<ImportDiagramDialog dialog={{ open: openImportDiagramDialog }} />
|
<ImportDiagramDialog dialog={{ open: openImportDiagramDialog }} />
|
||||||
|
<BuckleDialog dialog={{ open: openBuckleDialog }} />
|
||||||
</dialogContext.Provider>
|
</dialogContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ export interface LocalConfigContext {
|
|||||||
starUsDialogLastOpen: number;
|
starUsDialogLastOpen: number;
|
||||||
setStarUsDialogLastOpen: (lastOpen: number) => void;
|
setStarUsDialogLastOpen: (lastOpen: number) => void;
|
||||||
|
|
||||||
|
buckleWaitlistOpened: boolean;
|
||||||
|
setBuckleWaitlistOpened: (githubRepoOpened: boolean) => void;
|
||||||
|
|
||||||
|
buckleDialogLastOpen: number;
|
||||||
|
setBuckleDialogLastOpen: (lastOpen: number) => void;
|
||||||
|
|
||||||
showDependenciesOnCanvas: boolean;
|
showDependenciesOnCanvas: boolean;
|
||||||
setShowDependenciesOnCanvas: (showDependenciesOnCanvas: boolean) => void;
|
setShowDependenciesOnCanvas: (showDependenciesOnCanvas: boolean) => void;
|
||||||
}
|
}
|
||||||
@@ -56,6 +62,12 @@ export const LocalConfigContext = createContext<LocalConfigContext>({
|
|||||||
starUsDialogLastOpen: 0,
|
starUsDialogLastOpen: 0,
|
||||||
setStarUsDialogLastOpen: emptyFn,
|
setStarUsDialogLastOpen: emptyFn,
|
||||||
|
|
||||||
|
buckleWaitlistOpened: false,
|
||||||
|
setBuckleWaitlistOpened: emptyFn,
|
||||||
|
|
||||||
|
buckleDialogLastOpen: 0,
|
||||||
|
setBuckleDialogLastOpen: emptyFn,
|
||||||
|
|
||||||
showDependenciesOnCanvas: false,
|
showDependenciesOnCanvas: false,
|
||||||
setShowDependenciesOnCanvas: emptyFn,
|
setShowDependenciesOnCanvas: emptyFn,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ const showCardinalityKey = 'show_cardinality';
|
|||||||
const hideMultiSchemaNotificationKey = 'hide_multi_schema_notification';
|
const hideMultiSchemaNotificationKey = 'hide_multi_schema_notification';
|
||||||
const githubRepoOpenedKey = 'github_repo_opened';
|
const githubRepoOpenedKey = 'github_repo_opened';
|
||||||
const starUsDialogLastOpenKey = 'star_us_dialog_last_open';
|
const starUsDialogLastOpenKey = 'star_us_dialog_last_open';
|
||||||
|
const buckleWaitlistOpenedKey = 'buckle_waitlist_opened';
|
||||||
|
const buckleDialogLastOpenKey = 'buckle_dialog_last_open';
|
||||||
const showDependenciesOnCanvasKey = 'show_dependencies_on_canvas';
|
const showDependenciesOnCanvasKey = 'show_dependencies_on_canvas';
|
||||||
|
|
||||||
export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
|
export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
|
||||||
@@ -48,6 +50,17 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
parseInt(localStorage.getItem(starUsDialogLastOpenKey) || '0')
|
parseInt(localStorage.getItem(starUsDialogLastOpenKey) || '0')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [buckleWaitlistOpened, setBuckleWaitlistOpened] =
|
||||||
|
React.useState<boolean>(
|
||||||
|
(localStorage.getItem(buckleWaitlistOpenedKey) || 'false') ===
|
||||||
|
'true'
|
||||||
|
);
|
||||||
|
|
||||||
|
const [buckleDialogLastOpen, setBuckleDialogLastOpen] =
|
||||||
|
React.useState<number>(
|
||||||
|
parseInt(localStorage.getItem(buckleDialogLastOpenKey) || '0')
|
||||||
|
);
|
||||||
|
|
||||||
const [showDependenciesOnCanvas, setShowDependenciesOnCanvas] =
|
const [showDependenciesOnCanvas, setShowDependenciesOnCanvas] =
|
||||||
React.useState<boolean>(
|
React.useState<boolean>(
|
||||||
(localStorage.getItem(showDependenciesOnCanvasKey) || 'false') ===
|
(localStorage.getItem(showDependenciesOnCanvasKey) || 'false') ===
|
||||||
@@ -65,6 +78,20 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
localStorage.setItem(githubRepoOpenedKey, githubRepoOpened.toString());
|
localStorage.setItem(githubRepoOpenedKey, githubRepoOpened.toString());
|
||||||
}, [githubRepoOpened]);
|
}, [githubRepoOpened]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem(
|
||||||
|
buckleDialogLastOpenKey,
|
||||||
|
buckleDialogLastOpen.toString()
|
||||||
|
);
|
||||||
|
}, [buckleDialogLastOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem(
|
||||||
|
buckleWaitlistOpenedKey,
|
||||||
|
buckleWaitlistOpened.toString()
|
||||||
|
);
|
||||||
|
}, [buckleWaitlistOpened]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
hideMultiSchemaNotificationKey,
|
hideMultiSchemaNotificationKey,
|
||||||
@@ -114,6 +141,10 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
setStarUsDialogLastOpen,
|
setStarUsDialogLastOpen,
|
||||||
showDependenciesOnCanvas,
|
showDependenciesOnCanvas,
|
||||||
setShowDependenciesOnCanvas,
|
setShowDependenciesOnCanvas,
|
||||||
|
setBuckleDialogLastOpen,
|
||||||
|
buckleDialogLastOpen,
|
||||||
|
buckleWaitlistOpened,
|
||||||
|
setBuckleWaitlistOpened,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
80
src/dialogs/buckle-dialog/buckle-dialog.tsx
Normal file
80
src/dialogs/buckle-dialog/buckle-dialog.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React, { useCallback, useEffect } from 'react';
|
||||||
|
import { useDialog } from '@/hooks/use-dialog';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/dialog/dialog';
|
||||||
|
import { Button } from '@/components/button/button';
|
||||||
|
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||||
|
import { useLocalConfig } from '@/hooks/use-local-config';
|
||||||
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
|
|
||||||
|
export interface BuckleDialogProps extends BaseDialogProps {}
|
||||||
|
|
||||||
|
export const BuckleDialog: React.FC<BuckleDialogProps> = ({ dialog }) => {
|
||||||
|
const { setBuckleWaitlistOpened } = useLocalConfig();
|
||||||
|
const { effectiveTheme } = useTheme();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!dialog.open) return;
|
||||||
|
}, [dialog.open]);
|
||||||
|
const { closeBuckleDialog } = useDialog();
|
||||||
|
|
||||||
|
const handleConfirm = useCallback(() => {
|
||||||
|
setBuckleWaitlistOpened(true);
|
||||||
|
window.open('https://waitlist.buckle.dev', '_blank');
|
||||||
|
}, [setBuckleWaitlistOpened]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
{...dialog}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) {
|
||||||
|
closeBuckleDialog();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogContent
|
||||||
|
className="flex flex-col"
|
||||||
|
showClose={false}
|
||||||
|
onInteractOutside={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="hidden" />
|
||||||
|
<DialogDescription className="hidden" />
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="flex w-full flex-col items-center">
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
effectiveTheme === 'light'
|
||||||
|
? '/buckle-animated.gif'
|
||||||
|
: '/buckle.png'
|
||||||
|
}
|
||||||
|
className="h-16"
|
||||||
|
/>
|
||||||
|
<div className="mt-6 text-center text-base">
|
||||||
|
We've been working on something big -{' '}
|
||||||
|
<span className="font-semibold">Ready to explore?</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter className="flex gap-1 md:justify-between">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button variant="secondary">Not now</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button onClick={handleConfirm}>
|
||||||
|
Try ChartDB v2.0!
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -41,6 +41,10 @@ import { AlertProvider } from '@/context/alert-context/alert-provider';
|
|||||||
const OPEN_STAR_US_AFTER_SECONDS = 30;
|
const OPEN_STAR_US_AFTER_SECONDS = 30;
|
||||||
const SHOW_STAR_US_AGAIN_AFTER_DAYS = 1;
|
const SHOW_STAR_US_AGAIN_AFTER_DAYS = 1;
|
||||||
|
|
||||||
|
const OPEN_BUCKLE_AFTER_SECONDS = 60;
|
||||||
|
const SHOW_BUCKLE_AGAIN_AFTER_DAYS = 1;
|
||||||
|
const SHOW_BUCKLE_AGAIN_OPENED_AFTER_DAYS = 7;
|
||||||
|
|
||||||
export const EditorDesktopLayoutLazy = React.lazy(
|
export const EditorDesktopLayoutLazy = React.lazy(
|
||||||
() => import('./editor-desktop-layout')
|
() => import('./editor-desktop-layout')
|
||||||
);
|
);
|
||||||
@@ -60,7 +64,8 @@ const EditorPageComponent: React.FC = () => {
|
|||||||
const { openSelectSchema, showSidePanel } = useLayout();
|
const { openSelectSchema, showSidePanel } = useLayout();
|
||||||
const { resetRedoStack, resetUndoStack } = useRedoUndoStack();
|
const { resetRedoStack, resetUndoStack } = useRedoUndoStack();
|
||||||
const { showLoader, hideLoader } = useFullScreenLoader();
|
const { showLoader, hideLoader } = useFullScreenLoader();
|
||||||
const { openCreateDiagramDialog, openStarUsDialog } = useDialog();
|
const { openCreateDiagramDialog, openStarUsDialog, openBuckleDialog } =
|
||||||
|
useDialog();
|
||||||
const { diagramId } = useParams<{ diagramId: string }>();
|
const { diagramId } = useParams<{ diagramId: string }>();
|
||||||
const { config, updateConfig } = useConfig();
|
const { config, updateConfig } = useConfig();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -72,6 +77,9 @@ const EditorPageComponent: React.FC = () => {
|
|||||||
starUsDialogLastOpen,
|
starUsDialogLastOpen,
|
||||||
setStarUsDialogLastOpen,
|
setStarUsDialogLastOpen,
|
||||||
githubRepoOpened,
|
githubRepoOpened,
|
||||||
|
setBuckleDialogLastOpen,
|
||||||
|
buckleDialogLastOpen,
|
||||||
|
buckleWaitlistOpened,
|
||||||
} = useLocalConfig();
|
} = useLocalConfig();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -164,6 +172,33 @@ const EditorPageComponent: React.FC = () => {
|
|||||||
starUsDialogLastOpen,
|
starUsDialogLastOpen,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentDiagram?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
new Date().getTime() - buckleDialogLastOpen >
|
||||||
|
1000 *
|
||||||
|
60 *
|
||||||
|
60 *
|
||||||
|
24 *
|
||||||
|
(buckleWaitlistOpened
|
||||||
|
? SHOW_BUCKLE_AGAIN_OPENED_AFTER_DAYS
|
||||||
|
: SHOW_BUCKLE_AGAIN_AFTER_DAYS)
|
||||||
|
) {
|
||||||
|
const lastOpen = new Date().getTime();
|
||||||
|
setBuckleDialogLastOpen(lastOpen);
|
||||||
|
setTimeout(openBuckleDialog, OPEN_BUCKLE_AFTER_SECONDS * 1000);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
currentDiagram?.id,
|
||||||
|
buckleWaitlistOpened,
|
||||||
|
openBuckleDialog,
|
||||||
|
setBuckleDialogLastOpen,
|
||||||
|
buckleDialogLastOpen,
|
||||||
|
]);
|
||||||
|
|
||||||
const lastDiagramId = useRef<string>('');
|
const lastDiagramId = useRef<string>('');
|
||||||
|
|
||||||
const handleChangeSchema = useCallback(async () => {
|
const handleChangeSchema = useCallback(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user