mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-10-31 12:03:51 +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; | ||||
|     closeStarUsDialog: () => void; | ||||
|  | ||||
|     // Buckle dialog | ||||
|     openBuckleDialog: () => void; | ||||
|     closeBuckleDialog: () => void; | ||||
|  | ||||
|     // Export image dialog | ||||
|     openExportImageDialog: ( | ||||
|         params: Omit<ExportImageDialogProps, 'dialog'> | ||||
| @@ -80,4 +84,6 @@ export const dialogContext = createContext<DialogContext>({ | ||||
|     closeExportDiagramDialog: emptyFn, | ||||
|     openImportDiagramDialog: 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 { ExportDiagramDialog } from '@/dialogs/export-diagram-dialog/export-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> = ({ | ||||
|     children, | ||||
| @@ -27,6 +28,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|     const [openCreateRelationshipDialog, setOpenCreateRelationshipDialog] = | ||||
|         useState(false); | ||||
|     const [openStarUsDialog, setOpenStarUsDialog] = useState(false); | ||||
|     const [openBuckleDialog, setOpenBuckleDialog] = useState(false); | ||||
|  | ||||
|     // Export image dialog | ||||
|     const [openExportImageDialog, setOpenExportImageDialog] = useState(false); | ||||
| @@ -114,6 +116,8 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|                 closeTableSchemaDialog: () => setOpenTableSchemaDialog(false), | ||||
|                 openStarUsDialog: () => setOpenStarUsDialog(true), | ||||
|                 closeStarUsDialog: () => setOpenStarUsDialog(false), | ||||
|                 closeBuckleDialog: () => setOpenBuckleDialog(false), | ||||
|                 openBuckleDialog: () => setOpenBuckleDialog(true), | ||||
|                 closeExportImageDialog: () => setOpenExportImageDialog(false), | ||||
|                 openExportImageDialog: openExportImageDialogHandler, | ||||
|                 openExportDiagramDialog: () => setOpenExportDiagramDialog(true), | ||||
| @@ -149,6 +153,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|             /> | ||||
|             <ExportDiagramDialog dialog={{ open: openExportDiagramDialog }} /> | ||||
|             <ImportDiagramDialog dialog={{ open: openImportDiagramDialog }} /> | ||||
|             <BuckleDialog dialog={{ open: openBuckleDialog }} /> | ||||
|         </dialogContext.Provider> | ||||
|     ); | ||||
| }; | ||||
|   | ||||
| @@ -30,6 +30,12 @@ export interface LocalConfigContext { | ||||
|     starUsDialogLastOpen: number; | ||||
|     setStarUsDialogLastOpen: (lastOpen: number) => void; | ||||
|  | ||||
|     buckleWaitlistOpened: boolean; | ||||
|     setBuckleWaitlistOpened: (githubRepoOpened: boolean) => void; | ||||
|  | ||||
|     buckleDialogLastOpen: number; | ||||
|     setBuckleDialogLastOpen: (lastOpen: number) => void; | ||||
|  | ||||
|     showDependenciesOnCanvas: boolean; | ||||
|     setShowDependenciesOnCanvas: (showDependenciesOnCanvas: boolean) => void; | ||||
| } | ||||
| @@ -56,6 +62,12 @@ export const LocalConfigContext = createContext<LocalConfigContext>({ | ||||
|     starUsDialogLastOpen: 0, | ||||
|     setStarUsDialogLastOpen: emptyFn, | ||||
|  | ||||
|     buckleWaitlistOpened: false, | ||||
|     setBuckleWaitlistOpened: emptyFn, | ||||
|  | ||||
|     buckleDialogLastOpen: 0, | ||||
|     setBuckleDialogLastOpen: emptyFn, | ||||
|  | ||||
|     showDependenciesOnCanvas: false, | ||||
|     setShowDependenciesOnCanvas: emptyFn, | ||||
| }); | ||||
|   | ||||
| @@ -10,6 +10,8 @@ const showCardinalityKey = 'show_cardinality'; | ||||
| const hideMultiSchemaNotificationKey = 'hide_multi_schema_notification'; | ||||
| const githubRepoOpenedKey = 'github_repo_opened'; | ||||
| const starUsDialogLastOpenKey = 'star_us_dialog_last_open'; | ||||
| const buckleWaitlistOpenedKey = 'buckle_waitlist_opened'; | ||||
| const buckleDialogLastOpenKey = 'buckle_dialog_last_open'; | ||||
| const showDependenciesOnCanvasKey = 'show_dependencies_on_canvas'; | ||||
|  | ||||
| export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({ | ||||
| @@ -48,6 +50,17 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|             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] = | ||||
|         React.useState<boolean>( | ||||
|             (localStorage.getItem(showDependenciesOnCanvasKey) || 'false') === | ||||
| @@ -65,6 +78,20 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|         localStorage.setItem(githubRepoOpenedKey, githubRepoOpened.toString()); | ||||
|     }, [githubRepoOpened]); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         localStorage.setItem( | ||||
|             buckleDialogLastOpenKey, | ||||
|             buckleDialogLastOpen.toString() | ||||
|         ); | ||||
|     }, [buckleDialogLastOpen]); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         localStorage.setItem( | ||||
|             buckleWaitlistOpenedKey, | ||||
|             buckleWaitlistOpened.toString() | ||||
|         ); | ||||
|     }, [buckleWaitlistOpened]); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         localStorage.setItem( | ||||
|             hideMultiSchemaNotificationKey, | ||||
| @@ -114,6 +141,10 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({ | ||||
|                 setStarUsDialogLastOpen, | ||||
|                 showDependenciesOnCanvas, | ||||
|                 setShowDependenciesOnCanvas, | ||||
|                 setBuckleDialogLastOpen, | ||||
|                 buckleDialogLastOpen, | ||||
|                 buckleWaitlistOpened, | ||||
|                 setBuckleWaitlistOpened, | ||||
|             }} | ||||
|         > | ||||
|             {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 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( | ||||
|     () => import('./editor-desktop-layout') | ||||
| ); | ||||
| @@ -60,7 +64,8 @@ const EditorPageComponent: React.FC = () => { | ||||
|     const { openSelectSchema, showSidePanel } = useLayout(); | ||||
|     const { resetRedoStack, resetUndoStack } = useRedoUndoStack(); | ||||
|     const { showLoader, hideLoader } = useFullScreenLoader(); | ||||
|     const { openCreateDiagramDialog, openStarUsDialog } = useDialog(); | ||||
|     const { openCreateDiagramDialog, openStarUsDialog, openBuckleDialog } = | ||||
|         useDialog(); | ||||
|     const { diagramId } = useParams<{ diagramId: string }>(); | ||||
|     const { config, updateConfig } = useConfig(); | ||||
|     const navigate = useNavigate(); | ||||
| @@ -72,6 +77,9 @@ const EditorPageComponent: React.FC = () => { | ||||
|         starUsDialogLastOpen, | ||||
|         setStarUsDialogLastOpen, | ||||
|         githubRepoOpened, | ||||
|         setBuckleDialogLastOpen, | ||||
|         buckleDialogLastOpen, | ||||
|         buckleWaitlistOpened, | ||||
|     } = useLocalConfig(); | ||||
|     const { toast } = useToast(); | ||||
|     const { t } = useTranslation(); | ||||
| @@ -164,6 +172,33 @@ const EditorPageComponent: React.FC = () => { | ||||
|         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 handleChangeSchema = useCallback(async () => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user