mirror of https://github.com/buster-so/buster.git
app version updated
This commit is contained in:
parent
ddde4343d0
commit
bbcd0db69a
|
@ -0,0 +1,8 @@
|
|||
import { createServerFn } from '@tanstack/react-start';
|
||||
|
||||
export const getAppBuildId = createServerFn({ method: 'GET' }).handler(async () => {
|
||||
return {
|
||||
buildId: import.meta.env.VITE_BUILD_ID,
|
||||
buildAt: import.meta.env.VITE_BUILD_AT,
|
||||
};
|
||||
});
|
|
@ -24,11 +24,11 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
|||
toastOptions={{
|
||||
classNames: {
|
||||
toast:
|
||||
'group toast group-[.toaster]:bg-background! border !p-3 group-[.toaster]:text-foreground! group-[.toaster]:border-border! group-[.toaster]:shadow!',
|
||||
'group toast group-[.toaster]:bg-background border p-3 group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow',
|
||||
description: 'group-[.toast]:text-gray-light',
|
||||
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||
cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground',
|
||||
icon: 'mx-0! !flex !justify-center',
|
||||
icon: 'ml-0 mr-1 !flex !justify-center',
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getAppBuildId } from '@/api/server-functions/getAppVersion';
|
||||
import { Text } from '@/components/ui/typography';
|
||||
import { useWindowFocus } from '@/hooks/useWindowFocus';
|
||||
import { useBusterNotifications } from '../BusterNotifications';
|
||||
|
||||
const browserBuild = import.meta.env.VITE_BUILD_ID;
|
||||
|
||||
export const useAppVersion = () => {
|
||||
const { openInfoNotification } = useBusterNotifications();
|
||||
const { data, refetch, isFetched } = useQuery({
|
||||
queryKey: ['app-version'] as const,
|
||||
queryFn: getAppBuildId,
|
||||
refetchInterval: 20000, // 20 seconds
|
||||
});
|
||||
const isChanged = data?.buildId !== browserBuild && isFetched && browserBuild;
|
||||
|
||||
const reloadWindow = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
useWindowFocus(() => {
|
||||
refetch().then(() => {
|
||||
if (isChanged) {
|
||||
reloadWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isChanged) {
|
||||
openInfoNotification({
|
||||
duration: Infinity,
|
||||
title: 'New Version Available',
|
||||
message: <AppVersionMessage />,
|
||||
dismissible: false,
|
||||
className: 'min-w-[450px]',
|
||||
action: {
|
||||
label: 'Refresh',
|
||||
onClick: () => {
|
||||
reloadWindow();
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [isChanged]);
|
||||
};
|
||||
|
||||
const AppVersionMessage = () => {
|
||||
// const [countdown, setCountdown] = useState(30);
|
||||
// useEffect(() => {
|
||||
// const interval = setInterval(() => {
|
||||
// setCountdown((prev) => Math.max(prev - 1, 0));
|
||||
// if (countdown === 0) {
|
||||
// // window.location.reload();
|
||||
// }
|
||||
// }, 1000);
|
||||
// return () => clearInterval(interval);
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<Text>
|
||||
A new version of the app is available. Please refresh the page to get the latest features.
|
||||
</Text>
|
||||
);
|
||||
};
|
|
@ -12,16 +12,16 @@ const ConfirmModal = lazy(() =>
|
|||
import('@/components/ui/modal/ConfirmModal').then((mod) => ({ default: mod.ConfirmModal }))
|
||||
);
|
||||
|
||||
export interface NotificationProps {
|
||||
export type NotificationProps = {
|
||||
type?: NotificationType;
|
||||
title?: string;
|
||||
message?: string;
|
||||
message?: string | React.ReactNode;
|
||||
duration?: number;
|
||||
action?: {
|
||||
label: string;
|
||||
onClick: () => void | (() => Promise<void>);
|
||||
};
|
||||
}
|
||||
} & ExternalToast;
|
||||
|
||||
const openNotification = (props: NotificationProps) => {
|
||||
const { title, message, type } = props;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { BusterPosthogProvider } from '@/context/Posthog';
|
||||
import { useAppVersion } from './AppVersion/useAppVersion';
|
||||
import { BusterStyleProvider } from './BusterStyles';
|
||||
|
||||
import {
|
||||
SupabaseContextProvider,
|
||||
type SupabaseContextType,
|
||||
|
@ -16,6 +16,8 @@ export const AppProviders: React.FC<PropsWithChildren<SupabaseContextType>> = ({
|
|||
children,
|
||||
supabaseSession,
|
||||
}) => {
|
||||
useAppVersion();
|
||||
|
||||
return (
|
||||
<SupabaseContextProvider supabaseSession={supabaseSession}>
|
||||
<BusterPosthogProvider>{children}</BusterPosthogProvider>
|
||||
|
|
|
@ -28,6 +28,7 @@ export const Route = createFileRoute('/app/_app')({
|
|||
},
|
||||
component: () => {
|
||||
const { initialLayout, defaultLayout } = Route.useLoaderData();
|
||||
|
||||
return (
|
||||
<PrimaryAppLayout
|
||||
initialLayout={initialLayout}
|
||||
|
|
|
@ -13,8 +13,17 @@ const config = defineConfig(({ command, mode }) => {
|
|||
const isLocalBuild = process.argv.includes('--local') || mode === 'development';
|
||||
const target = isLocalBuild ? ('bun' as const) : ('vercel' as const);
|
||||
|
||||
// Generate a unique build ID for cache busting after deployments
|
||||
const buildId = `build:${process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 8) || process.env.BUILD_ID || Date.now().toString()}`;
|
||||
const buildAt = new Date().toISOString();
|
||||
|
||||
return {
|
||||
server: { port: 3000 },
|
||||
define: {
|
||||
// Make the build ID available to the app for version tracking
|
||||
'import.meta.env.VITE_BUILD_ID': JSON.stringify(buildId),
|
||||
'import.meta.env.VITE_BUILD_AT': JSON.stringify(buildAt),
|
||||
},
|
||||
plugins: [
|
||||
// this is the plugin that enables path aliases
|
||||
viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
|
||||
|
|
Loading…
Reference in New Issue