Added persistent statuses.

This commit is contained in:
2025-10-27 16:00:45 -05:00
parent 4306d69558
commit d2517901a8
12 changed files with 163 additions and 77 deletions

View File

@@ -12,11 +12,11 @@
}, },
"dependencies": { "dependencies": {
"@expo/vector-icons": "^15.0.3", "@expo/vector-icons": "^15.0.3",
"@react-navigation/bottom-tabs": "^7.5.0", "@react-navigation/bottom-tabs": "^7.6.0",
"@react-navigation/elements": "^2.7.0", "@react-navigation/elements": "^2.7.1",
"@react-navigation/native": "^7.1.18", "@react-navigation/native": "^7.1.19",
"@sentry/react-native": "^7.4.0", "@sentry/react-native": "^7.4.0",
"expo": "~54.0.19", "expo": "~54.0.20",
"expo-apple-authentication": "~8.0.7", "expo-apple-authentication": "~8.0.7",
"expo-constants": "~18.0.10", "expo-constants": "~18.0.10",
"expo-font": "~14.0.9", "expo-font": "~14.0.9",

View File

@@ -26,7 +26,7 @@
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tabs": "^1.1.13",
"@sentry/nextjs": "^10.21.0", "@sentry/nextjs": "^10.22.0",
"@t3-oss/env-nextjs": "^0.13.8", "@t3-oss/env-nextjs": "^0.13.8",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",

View File

@@ -10,9 +10,11 @@ import {
Button, Button,
Card, Card,
CardContent, CardContent,
Checkbox,
Drawer, Drawer,
DrawerTrigger, DrawerTrigger,
Input, Input,
Label,
SubmitButton, SubmitButton,
Tabs, Tabs,
TabsContent, TabsContent,
@@ -49,6 +51,7 @@ export const StatusList = ({
const [selectedUserIds, setSelectedUserIds] = useState<Id<'users'>[]>([]); const [selectedUserIds, setSelectedUserIds] = useState<Id<'users'>[]>([]);
const [selectAll, setSelectAll] = useState(false); const [selectAll, setSelectAll] = useState(false);
const [statusInput, setStatusInput] = useState(''); const [statusInput, setStatusInput] = useState('');
const [persistStatus, setPersistStatus] = useState(false);
const [updatingStatus, setUpdatingStatus] = useState(false); const [updatingStatus, setUpdatingStatus] = useState(false);
const [animatingIds, setAnimatingIds] = useState<Set<string>>(new Set()); const [animatingIds, setAnimatingIds] = useState<Set<string>>(new Set());
const [previousStatuses, setPreviousStatuses] = useState(statuses); const [previousStatuses, setPreviousStatuses] = useState(statuses);
@@ -98,11 +101,24 @@ export const StatusList = ({
throw new Error('Status must be between 3 & 80 characters'); throw new Error('Status must be between 3 & 80 characters');
} }
if (selectedUserIds.length === 0 && user?.id) { if (selectedUserIds.length === 0 && user?.id) {
await bulkCreate({ message, userIds: [user.id] }); await bulkCreate({
message,
userIds: [user.id],
persistentStatus: persistStatus
});
} else { } else {
await bulkCreate({ message, userIds: selectedUserIds }); await bulkCreate({
message,
userIds: selectedUserIds,
persistentStatus: persistStatus
});
} }
toast.success('Status updated.'); toast.success('Status updated.');
toast.success('Status updated.', {
duration: 2000,
closeButton: true,
dismissible: true,
});
setSelectedUserIds([]); setSelectedUserIds([]);
setSelectAll(false); setSelectAll(false);
setStatusInput(''); setStatusInput('');
@@ -149,13 +165,13 @@ export const StatusList = ({
<TabsList className={tabsCn}> <TabsList className={tabsCn}>
<TabsTrigger value='status' className='py-3 sm:py-8'> <TabsTrigger value='status' className='py-3 sm:py-8'>
<div className='flex items-center gap-2 sm:gap-3'> <div className='flex items-center gap-2 sm:gap-3'>
<Activity className='text-primary w-4 h-4 sm:w-5 sm:h-5' /> <Activity className='text-primary sm:scale-150' />
<h1 className='text-base sm:text-2xl font-bold'>Team Status</h1> <h1 className='text-base sm:text-2xl font-bold'>Status List</h1>
</div> </div>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value='history' className='py-3 sm:py-8'> <TabsTrigger value='history' className='py-3 sm:py-8'>
<div className='flex items-center gap-2 sm:gap-3'> <div className='flex items-center gap-2 sm:gap-3'>
<History className='text-primary w-4 h-4 sm:w-5 sm:h-5' /> <History className='text-primary sm:scale-150' />
<h1 className='text-base sm:text-2xl font-bold'> <h1 className='text-base sm:text-2xl font-bold'>
Status History Status History
</h1> </h1>
@@ -216,6 +232,7 @@ export const StatusList = ({
className={` className={`
relative rounded-xl border transition-all relative rounded-xl border transition-all
${isAnimating ? 'bg-primary/5 border-primary/30' : ''} ${isAnimating ? 'bg-primary/5 border-primary/30' : ''}
${s?.persistentStatus ? 'bg-black/10' : ''}
${ ${
isSelected isSelected
? 'border-primary bg-primary/5' ? 'border-primary bg-primary/5'
@@ -236,7 +253,7 @@ export const StatusList = ({
<div className='flex items-start gap-3 sm:gap-4'> <div className='flex items-start gap-3 sm:gap-4'>
{/* Avatar */} {/* Avatar */}
<div className='flex-shrink-0'> <div className='shrink-0'>
<BasedAvatar <BasedAvatar
src={u.imageUrl} src={u.imageUrl}
fullName={u.name ?? 'User'} fullName={u.name ?? 'User'}
@@ -295,11 +312,7 @@ export const StatusList = ({
</div> </div>
{/* Meta - only show here when NOT in TV mode */} {/* Meta - only show here when NOT in TV mode */}
{!tvMode && ( {!tvMode && (
<div <div className='flex items-center text-muted-foreground gap-3 sm:gap-4'>
className={`
flex items-center text-muted-foreground gap-3 sm:gap-4
`}
>
<div className='flex items-center gap-1.5'> <div className='flex items-center gap-1.5'>
<Clock className='w-4 h-4 sm:w-4 sm:h-4' /> <Clock className='w-4 h-4 sm:w-4 sm:h-4' />
<span className='text-sm sm:text-lg'> <span className='text-sm sm:text-lg'>
@@ -401,9 +414,10 @@ export const StatusList = ({
> >
<CardContent className='p-6'> <CardContent className='p-6'>
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
<div className='flex items-center gap-3'> <div className='flex gap-3 w-full justify-between'>
<Zap className='w-5 h-5 text-primary' /> <div className='flex gap-3 items-center'>
<h3 className='text-lg font-semibold'>Update Status</h3> <Zap className='w-6 h-6 text-primary' />
<h3 className='text-xl font-semibold'>Update Status</h3>
{selectedUserIds.length > 0 && ( {selectedUserIds.length > 0 && (
<span <span
className='px-2 py-1 bg-primary/10 text-primary className='px-2 py-1 bg-primary/10 text-primary
@@ -413,6 +427,17 @@ export const StatusList = ({
</span> </span>
)} )}
</div> </div>
<div className='flex space-x-2 items-center'>
<Checkbox
checked={persistStatus}
className='border border-primary'
onCheckedChange={() => setPersistStatus(!persistStatus)}
/>
<Label>
Persist Status
</Label>
</div>
</div>
<div className='flex gap-3'> <div className='flex gap-3'>
<Input <Input
autoFocus autoFocus
@@ -469,7 +494,7 @@ export const StatusList = ({
<div <div
className='md:hidden fixed bottom-0 left-0 right-0 z-50 className='md:hidden fixed bottom-0 left-0 right-0 z-50
border-t bg-background/95 backdrop-blur border-t bg-background/95 backdrop-blur
supports-[backdrop-filter]:bg-background/60 p-3 supports-backdrop-filter:bg-background/60 p-3
pb-[calc(0.75rem+env(safe-area-inset-bottom))]' pb-[calc(0.75rem+env(safe-area-inset-bottom))]'
> >
<div className='flex items-center justify-between mb-2'> <div className='flex items-center justify-between mb-2'>
@@ -482,6 +507,16 @@ export const StatusList = ({
Update your status Update your status
</span> </span>
)} )}
<div className='flex flex-row space-x-2'>
<Checkbox
className='border border-primary'
checked={persistStatus}
onCheckedChange={() => setPersistStatus(!persistStatus)}
/>
<Label className='text-xs'>
Persist Status
</Label>
</div>
<Button variant='outline' size='sm' onClick={handleSelectAll}> <Button variant='outline' size='sm' onClick={handleSelectAll}>
{selectAll ? 'Clear' : 'Select all'} {selectAll ? 'Clear' : 'Select all'}
</Button> </Button>

View File

@@ -51,7 +51,8 @@ export const formatDate = (timestamp: Timestamp, locale = 'en-US'): string => {
const date = toDate(timestamp); const date = toDate(timestamp);
if (!date) return '--/--'; if (!date) return '--/--';
return date.toLocaleDateString(locale, { return date.toLocaleDateString(locale, {
month: 'long', weekday: 'long',
month: 'short',
day: 'numeric', day: 'numeric',
}); });
}; };

View File

@@ -16,11 +16,11 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@expo/vector-icons": "^15.0.3", "@expo/vector-icons": "^15.0.3",
"@react-navigation/bottom-tabs": "^7.5.0", "@react-navigation/bottom-tabs": "^7.6.0",
"@react-navigation/elements": "^2.7.0", "@react-navigation/elements": "^2.7.1",
"@react-navigation/native": "^7.1.18", "@react-navigation/native": "^7.1.19",
"@sentry/react-native": "^7.4.0", "@sentry/react-native": "^7.4.0",
"expo": "~54.0.19", "expo": "~54.0.20",
"expo-apple-authentication": "~8.0.7", "expo-apple-authentication": "~8.0.7",
"expo-constants": "~18.0.10", "expo-constants": "~18.0.10",
"expo-font": "~14.0.9", "expo-font": "~14.0.9",
@@ -1049,13 +1049,13 @@
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.4", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-hBM+rMyL6Wm1Q4f/WpqGsaCojKSNUBqAXLABNGoWm1vabZ7cSnARMxBvA/2vo3hLcoR4v7zDK8tkKm9+O0LjVA=="], "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.4", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-hBM+rMyL6Wm1Q4f/WpqGsaCojKSNUBqAXLABNGoWm1vabZ7cSnARMxBvA/2vo3hLcoR4v7zDK8tkKm9+O0LjVA=="],
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.5.0", "", { "dependencies": { "@react-navigation/elements": "^2.7.0", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.18", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-JY9yQDQTv7avXqXdrToyn6ogcBqY2gTXg7C1J6OWZGz7QhlnPZQm375T4nYBWqVWsODVNeNagkCPptZGOxI1rg=="], "@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.6.0", "", { "dependencies": { "@react-navigation/elements": "^2.7.1", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.19", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-5qnicy9SdgnCjEj6wNiJiKgxHtP7gtLi8+owxRy1HatgNknQyIS00dFWlzxHLiRnU5zuIUtX2/9DZoDLrLyrTQ=="],
"@react-navigation/core": ["@react-navigation/core@7.12.4", "", { "dependencies": { "@react-navigation/routers": "^7.5.1", "escape-string-regexp": "^4.0.0", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-xLFho76FA7v500XID5z/8YfGTvjQPw7/fXsq4BIrVSqetNe/o/v+KAocEw4ots6kyv3XvSTyiWKh2g3pN6xZ9Q=="], "@react-navigation/core": ["@react-navigation/core@7.13.0", "", { "dependencies": { "@react-navigation/routers": "^7.5.1", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-Fc/SO23HnlGnkou/z8JQUzwEMvhxuUhr4rdPTIZp/c8q1atq3k632Nfh8fEiGtk+MP1wtIvXdN2a5hBIWpLq3g=="],
"@react-navigation/elements": ["@react-navigation/elements@2.7.0", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.18", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-lqlUUTqzKJrm3WYmiy901DSpa5wW8DWSmqNqWlRFWDVjx6SSjOUThQpdMnVXhydPtrTo74yVUPB27oe/jrvo4Q=="], "@react-navigation/elements": ["@react-navigation/elements@2.7.1", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.19", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-IZO8lx8+ftfbBdaL79FB4mo8PuaMLHnGt4iPLx0TRocIaHHUaPcb4R1ble1DGKeRuyeBbFHu2uLTD1YRDE0lsg=="],
"@react-navigation/native": ["@react-navigation/native@7.1.18", "", { "dependencies": { "@react-navigation/core": "^7.12.4", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-DZgd6860dxcq3YX7UzIXeBr6m3UgXvo9acxp5jiJyIZXdR00Br9JwVkO7e0bUeTA2d3Z8dsmtAR84Y86NnH64Q=="], "@react-navigation/native": ["@react-navigation/native@7.1.19", "", { "dependencies": { "@react-navigation/core": "^7.13.0", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-fM7q8di4Q8sp2WUhiUWOe7bEDRyRhbzsKQOd5N2k+lHeCx3UncsRYuw4Q/KN0EovM3wWKqMMmhy/YWuEO04kgw=="],
"@react-navigation/native-stack": ["@react-navigation/native-stack@7.3.26", "", { "dependencies": { "@react-navigation/elements": "^2.6.4", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.17", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-EjaBWzLZ76HJGOOcWCFf+h/M+Zg7M1RalYioDOb6ZdXHz7AwYNidruT3OUAQgSzg3gVLqvu5OYO0jFsNDPCZxQ=="], "@react-navigation/native-stack": ["@react-navigation/native-stack@7.3.26", "", { "dependencies": { "@react-navigation/elements": "^2.6.4", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.17", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-EjaBWzLZ76HJGOOcWCFf+h/M+Zg7M1RalYioDOb6ZdXHz7AwYNidruT3OUAQgSzg3gVLqvu5OYO0jFsNDPCZxQ=="],
@@ -1115,7 +1115,7 @@
"@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], "@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="],
"@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.21.0", "", { "dependencies": { "@sentry/core": "10.21.0" } }, "sha512-QRHpCBheLd/88Z2m3ABMriV0MweW+pcGKuVsH61/UdziKcQLdoQpOSvGg0/0CuqFm2UjL7237ZzLdZrWaCOlfQ=="], "@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.22.0", "", { "dependencies": { "@sentry/core": "10.22.0" } }, "sha512-BpJoLZEyJr7ORzkCrIjxRTnFWwO1mJNICVh3B9g5d9245niGT4OJvRozmLz89WgJkZFHWu84ls6Xfq5b/3tGFQ=="],
"@sentry-internal/feedback": ["@sentry-internal/feedback@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-R/eGLKl7WDccLKBorEbyTsy5b99w/k4v80SntE8HL2rsO7DCDXma8TGmtHd+iZnw8dUci+EVrw7LbeGSgf3QzA=="], "@sentry-internal/feedback": ["@sentry-internal/feedback@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-R/eGLKl7WDccLKBorEbyTsy5b99w/k4v80SntE8HL2rsO7DCDXma8TGmtHd+iZnw8dUci+EVrw7LbeGSgf3QzA=="],
@@ -1149,13 +1149,13 @@
"@sentry/core": ["@sentry/core@10.20.0", "", {}, "sha512-S291KihnOIB8i7mVJIJBVHBMcCfIoY/KDJBHEfBoHY9M56g2An4FVhM9+/xR85+IoMkTySdXN08k9LEyQz4FpQ=="], "@sentry/core": ["@sentry/core@10.20.0", "", {}, "sha512-S291KihnOIB8i7mVJIJBVHBMcCfIoY/KDJBHEfBoHY9M56g2An4FVhM9+/xR85+IoMkTySdXN08k9LEyQz4FpQ=="],
"@sentry/nextjs": ["@sentry/nextjs@10.21.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@rollup/plugin-commonjs": "28.0.1", "@sentry-internal/browser-utils": "10.21.0", "@sentry/bundler-plugin-core": "^4.3.0", "@sentry/core": "10.21.0", "@sentry/node": "10.21.0", "@sentry/opentelemetry": "10.21.0", "@sentry/react": "10.21.0", "@sentry/vercel-edge": "10.21.0", "@sentry/webpack-plugin": "^4.3.0", "chalk": "3.0.0", "resolve": "1.22.8", "rollup": "^4.35.0", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "next": "^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0" } }, "sha512-Y2mCr7xobgc+Z8PAP46k07y9Dp2lW7orKms/VRjXRm9G+b67KDH88Crnk8Hdlo7R7WNwmRRvDnMzU2bphoeIug=="], "@sentry/nextjs": ["@sentry/nextjs@10.22.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@rollup/plugin-commonjs": "28.0.1", "@sentry-internal/browser-utils": "10.22.0", "@sentry/bundler-plugin-core": "^4.3.0", "@sentry/core": "10.22.0", "@sentry/node": "10.22.0", "@sentry/opentelemetry": "10.22.0", "@sentry/react": "10.22.0", "@sentry/vercel-edge": "10.22.0", "@sentry/webpack-plugin": "^4.3.0", "resolve": "1.22.8", "rollup": "^4.35.0", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "next": "^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0" } }, "sha512-9Np176cDMLTl98QRqESe6STyaQ0SKiWTDRdF3GPYPEB9s4t5Qz2zZJ9A40Fz3fZ33kW4Z/qscDx3WpCwFLe5Bg=="],
"@sentry/node": ["@sentry/node@10.21.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.1.0", "@opentelemetry/core": "^2.1.0", "@opentelemetry/instrumentation": "^0.204.0", "@opentelemetry/instrumentation-amqplib": "0.51.0", "@opentelemetry/instrumentation-connect": "0.48.0", "@opentelemetry/instrumentation-dataloader": "0.22.0", "@opentelemetry/instrumentation-express": "0.53.0", "@opentelemetry/instrumentation-fs": "0.24.0", "@opentelemetry/instrumentation-generic-pool": "0.48.0", "@opentelemetry/instrumentation-graphql": "0.52.0", "@opentelemetry/instrumentation-hapi": "0.51.0", "@opentelemetry/instrumentation-http": "0.204.0", "@opentelemetry/instrumentation-ioredis": "0.52.0", "@opentelemetry/instrumentation-kafkajs": "0.14.0", "@opentelemetry/instrumentation-knex": "0.49.0", "@opentelemetry/instrumentation-koa": "0.52.0", "@opentelemetry/instrumentation-lru-memoizer": "0.49.0", "@opentelemetry/instrumentation-mongodb": "0.57.0", "@opentelemetry/instrumentation-mongoose": "0.51.0", "@opentelemetry/instrumentation-mysql": "0.50.0", "@opentelemetry/instrumentation-mysql2": "0.51.0", "@opentelemetry/instrumentation-pg": "0.57.0", "@opentelemetry/instrumentation-redis": "0.53.0", "@opentelemetry/instrumentation-tedious": "0.23.0", "@opentelemetry/instrumentation-undici": "0.15.0", "@opentelemetry/resources": "^2.1.0", "@opentelemetry/sdk-trace-base": "^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@prisma/instrumentation": "6.15.0", "@sentry/core": "10.21.0", "@sentry/node-core": "10.21.0", "@sentry/opentelemetry": "10.21.0", "import-in-the-middle": "^1.14.2", "minimatch": "^9.0.0" } }, "sha512-z7g+rZIHOSzISGCYbpy8b6UxYd7kl0bjdTTjDC4rJCoofhO71By5tZum1HhcmYEWWDj7qc/Mbfmfv6rXoimT6A=="], "@sentry/node": ["@sentry/node@10.22.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.1.0", "@opentelemetry/core": "^2.1.0", "@opentelemetry/instrumentation": "^0.204.0", "@opentelemetry/instrumentation-amqplib": "0.51.0", "@opentelemetry/instrumentation-connect": "0.48.0", "@opentelemetry/instrumentation-dataloader": "0.22.0", "@opentelemetry/instrumentation-express": "0.53.0", "@opentelemetry/instrumentation-fs": "0.24.0", "@opentelemetry/instrumentation-generic-pool": "0.48.0", "@opentelemetry/instrumentation-graphql": "0.52.0", "@opentelemetry/instrumentation-hapi": "0.51.0", "@opentelemetry/instrumentation-http": "0.204.0", "@opentelemetry/instrumentation-ioredis": "0.52.0", "@opentelemetry/instrumentation-kafkajs": "0.14.0", "@opentelemetry/instrumentation-knex": "0.49.0", "@opentelemetry/instrumentation-koa": "0.52.0", "@opentelemetry/instrumentation-lru-memoizer": "0.49.0", "@opentelemetry/instrumentation-mongodb": "0.57.0", "@opentelemetry/instrumentation-mongoose": "0.51.0", "@opentelemetry/instrumentation-mysql": "0.50.0", "@opentelemetry/instrumentation-mysql2": "0.51.0", "@opentelemetry/instrumentation-pg": "0.57.0", "@opentelemetry/instrumentation-redis": "0.53.0", "@opentelemetry/instrumentation-tedious": "0.23.0", "@opentelemetry/instrumentation-undici": "0.15.0", "@opentelemetry/resources": "^2.1.0", "@opentelemetry/sdk-trace-base": "^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0", "@prisma/instrumentation": "6.15.0", "@sentry/core": "10.22.0", "@sentry/node-core": "10.22.0", "@sentry/opentelemetry": "10.22.0", "import-in-the-middle": "^1.14.2", "minimatch": "^9.0.0" } }, "sha512-PfG8AMT2kgFJ7rWb0lLJOmjLW2riytTliLMjfoJ8/tLGk964uKqE0xM7FLtXZjlLJqTXVYCVG7VIPj185uyckQ=="],
"@sentry/node-core": ["@sentry/node-core@10.21.0", "", { "dependencies": { "@apm-js-collab/tracing-hooks": "^0.3.1", "@sentry/core": "10.21.0", "@sentry/opentelemetry": "10.21.0", "import-in-the-middle": "^1.14.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-vPn9sYMl2IB14lp6HP3nyJVM2VDDpclf7yvNWe/9yDY+ad1T/+8x5j501LjUaZDRR+7APM1Mb1S9YMAL3gTiwA=="], "@sentry/node-core": ["@sentry/node-core@10.22.0", "", { "dependencies": { "@apm-js-collab/tracing-hooks": "^0.3.1", "@sentry/core": "10.22.0", "@sentry/opentelemetry": "10.22.0", "import-in-the-middle": "^1.14.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/resources": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-88Yyn+Qvmp0kPMnNRWgpUlAvhI9CNPqOT+0glW0L7OoN8LkJcNgx2GGUoLrJ+RGeHz/S7dIJY6DGa+u0Not2Qg=="],
"@sentry/opentelemetry": ["@sentry/opentelemetry@10.21.0", "", { "dependencies": { "@sentry/core": "10.21.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-Yr4imXxkSLhJt2WHVXh31NpIe9ZgcnJTVVvzq/g6Ox40bj5+cdpFh6RTsLcsw5hvDC8a1KUvmdIhUTKAkEsqgA=="], "@sentry/opentelemetry": ["@sentry/opentelemetry@10.22.0", "", { "dependencies": { "@sentry/core": "10.22.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.37.0" } }, "sha512-XHXYYq3zsQ/dj1kQ7cGGLFIEVRmrmjcMhiJHvmKKsUGKxQjHe2G0LuG8clHIPkmbg7yEIxCT/W2I9QzrwYt5+g=="],
"@sentry/react": ["@sentry/react@10.20.0", "", { "dependencies": { "@sentry/browser": "10.20.0", "@sentry/core": "10.20.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-8W+gMkMxQhqlGHCW7kjLhcLgBJ/YSHbLhVd36s0GRudxjXh61K8rdCaAXToD8akgZ76DtLbx5PPQ5fLfQCOnpw=="], "@sentry/react": ["@sentry/react@10.20.0", "", { "dependencies": { "@sentry/browser": "10.20.0", "@sentry/core": "10.20.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-8W+gMkMxQhqlGHCW7kjLhcLgBJ/YSHbLhVd36s0GRudxjXh61K8rdCaAXToD8akgZ76DtLbx5PPQ5fLfQCOnpw=="],
@@ -1163,7 +1163,7 @@
"@sentry/types": ["@sentry/types@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-9pGtoiYBvw0SpHayBlQ6/9F4wP/KwlS8KZg1iBsZSR8h8WjLRGbER/TjKcAdg07HPd0APVajbT2YyL30+9Oi8Q=="], "@sentry/types": ["@sentry/types@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-9pGtoiYBvw0SpHayBlQ6/9F4wP/KwlS8KZg1iBsZSR8h8WjLRGbER/TjKcAdg07HPd0APVajbT2YyL30+9Oi8Q=="],
"@sentry/vercel-edge": ["@sentry/vercel-edge@10.21.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/resources": "^2.1.0", "@sentry/core": "10.21.0" } }, "sha512-bQ77ObqX0i0UbznfwA5Ji+5pnECyc6xtrJmxrE8w/BZXCME4ZfTRbHGt9XRn7l5TMp0+gPnLih4PawJcMFJKeA=="], "@sentry/vercel-edge": ["@sentry/vercel-edge@10.22.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/resources": "^2.1.0", "@sentry/core": "10.22.0" } }, "sha512-N6/4BrnqTJND/E1wxrQuiMKjJQ6W9xC/gibxrEfbZMFYU6VMz9/Quz+btfFJRsOiuFarLK8J/iEvWVB3mjZdzw=="],
"@sentry/webpack-plugin": ["@sentry/webpack-plugin@4.3.0", "", { "dependencies": { "@sentry/bundler-plugin-core": "4.3.0", "unplugin": "1.0.1", "uuid": "^9.0.0" }, "peerDependencies": { "webpack": ">=4.40.0" } }, "sha512-K4nU1SheK/tvyakBws2zfd+MN6hzmpW+wPTbSbDWn1+WL9+g9hsPh8hjFFiVe47AhhUoUZ3YgiH2HyeHXjHflA=="], "@sentry/webpack-plugin": ["@sentry/webpack-plugin@4.3.0", "", { "dependencies": { "@sentry/bundler-plugin-core": "4.3.0", "unplugin": "1.0.1", "uuid": "^9.0.0" }, "peerDependencies": { "webpack": ">=4.40.0" } }, "sha512-K4nU1SheK/tvyakBws2zfd+MN6hzmpW+wPTbSbDWn1+WL9+g9hsPh8hjFFiVe47AhhUoUZ3YgiH2HyeHXjHflA=="],
@@ -1777,7 +1777,7 @@
"exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="], "exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="],
"expo": ["expo@54.0.19", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.13", "@expo/config": "~12.0.10", "@expo/config-plugins": "~54.0.2", "@expo/devtools": "0.1.7", "@expo/fingerprint": "0.15.2", "@expo/metro": "~54.1.0", "@expo/metro-config": "54.0.7", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.6", "expo-asset": "~12.0.9", "expo-constants": "~18.0.10", "expo-file-system": "~19.0.17", "expo-font": "~14.0.9", "expo-keep-awake": "~15.0.7", "expo-modules-autolinking": "3.0.18", "expo-modules-core": "3.0.22", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-ZbCwBfrYnW7p5P9KGP/Dj9B79EpqP1au8qVDtwqqv6lOVHAYE3SWiooiZK9P8Nx3iViAVL11SF+HLOTPX+kaqA=="], "expo": ["expo@54.0.20", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.13", "@expo/config": "~12.0.10", "@expo/config-plugins": "~54.0.2", "@expo/devtools": "0.1.7", "@expo/fingerprint": "0.15.2", "@expo/metro": "~54.1.0", "@expo/metro-config": "54.0.7", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.6", "expo-asset": "~12.0.9", "expo-constants": "~18.0.10", "expo-file-system": "~19.0.17", "expo-font": "~14.0.9", "expo-keep-awake": "~15.0.7", "expo-modules-autolinking": "3.0.19", "expo-modules-core": "3.0.22", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-mWHky+H63W60P5Oo+VbtqzF2sLvdaoSSwG57H9rlq1DrgIla++QJZuwJkXXo55lYPymVmkVhwG6FjWYKKylwpw=="],
"expo-apple-authentication": ["expo-apple-authentication@8.0.7", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-KHLKecxwlPm42W/JYEefcFcXu5BW88wlgKSoikOFwRoWpzzryJxsNacMJRqrzAP3lFecPAK+ATgyJYvFkp10kw=="], "expo-apple-authentication": ["expo-apple-authentication@8.0.7", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-KHLKecxwlPm42W/JYEefcFcXu5BW88wlgKSoikOFwRoWpzzryJxsNacMJRqrzAP3lFecPAK+ATgyJYvFkp10kw=="],
@@ -1799,7 +1799,7 @@
"expo-location": ["expo-location@19.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-YNkh4r9E6ECbPkBCAMG5A5yHDgS0pw+Rzyd0l2ZQlCtjkhlODB55nMCKr5CZnUI0mXTkaSm8CwfoCO8n2MpYfg=="], "expo-location": ["expo-location@19.0.7", "", { "peerDependencies": { "expo": "*" } }, "sha512-YNkh4r9E6ECbPkBCAMG5A5yHDgS0pw+Rzyd0l2ZQlCtjkhlODB55nMCKr5CZnUI0mXTkaSm8CwfoCO8n2MpYfg=="],
"expo-modules-autolinking": ["expo-modules-autolinking@3.0.18", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-zanQWn4QrqJtyYGHUdL6OqjU8LKXIOgqF1PAkpNV33SPNb2ZFMBxM4vB1Y8EvqGeoouV7zRqxgXtXvDkAIFndA=="], "expo-modules-autolinking": ["expo-modules-autolinking@3.0.19", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-tSMYGnfZmAaN77X8iMLiaSgbCFnA7eh6s2ac09J2N2N0Rcf2RCE27jg0c0XenTMTWUcM4QvLhsNHof/WtlKqPw=="],
"expo-modules-core": ["expo-modules-core@3.0.22", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-FqG5oelITFTLcIfGwoJP8Qsk65be/eiEjz354NdAurnhFARHAVYOOIsUehArvm75ISdZOIZEaTSjCudmkA3kKg=="], "expo-modules-core": ["expo-modules-core@3.0.22", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-FqG5oelITFTLcIfGwoJP8Qsk65be/eiEjz354NdAurnhFARHAVYOOIsUehArvm75ISdZOIZEaTSjCudmkA3kKg=="],
@@ -3063,7 +3063,7 @@
"@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"@sentry-internal/browser-utils/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="], "@sentry-internal/browser-utils/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@sentry-internal/replay/@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-9+NybrYs+dEM2iW5uRAYEhKkNK0XhDea5jovtDUXEvdSCMJFcdR88uztkftnCur45/hpvbgSULsGPUdHPb5ITw=="], "@sentry-internal/replay/@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.20.0", "", { "dependencies": { "@sentry/core": "10.20.0" } }, "sha512-9+NybrYs+dEM2iW5uRAYEhKkNK0XhDea5jovtDUXEvdSCMJFcdR88uztkftnCur45/hpvbgSULsGPUdHPb5ITw=="],
@@ -3077,21 +3077,19 @@
"@sentry/bundler-plugin-core/magic-string": ["magic-string@0.30.8", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ=="], "@sentry/bundler-plugin-core/magic-string": ["magic-string@0.30.8", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ=="],
"@sentry/nextjs/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="], "@sentry/nextjs/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@sentry/nextjs/@sentry/react": ["@sentry/react@10.21.0", "", { "dependencies": { "@sentry/browser": "10.21.0", "@sentry/core": "10.21.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-BSCGKkepg9QPJRS8AUjtSAFd4lYJLmz3+P+oehViEHQDtRqqmXbVIBLhqwPc05KvRGIl4/kIDjyfDuHCFCJigQ=="], "@sentry/nextjs/@sentry/react": ["@sentry/react@10.22.0", "", { "dependencies": { "@sentry/browser": "10.22.0", "@sentry/core": "10.22.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-XByOjtW30LMNibmCPJF5LNYFmETNOUmWByECADox8GYV4BEX18WGXl4K1fpPDTSk+y4vUCHbltHa4GkyTRwG8Q=="],
"@sentry/nextjs/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], "@sentry/node/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@sentry/node/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="],
"@sentry/node/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@sentry/node/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@sentry/node-core/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="], "@sentry/node-core/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@sentry/opentelemetry/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="], "@sentry/opentelemetry/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@sentry/vercel-edge/@sentry/core": ["@sentry/core@10.21.0", "", {}, "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA=="], "@sentry/vercel-edge/@sentry/core": ["@sentry/core@10.22.0", "", {}, "sha512-V1oeHbrOKzxadsCmgtPku3v3Emo/Bpb3VSuKmlLrQefiHX98MWtjJ3XDGfduzD5/dCdh0r/OOLwjcmrO/PZ2aw=="],
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
@@ -3247,6 +3245,10 @@
"expo-router/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], "expo-router/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
"expo-router/@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.5.0", "", { "dependencies": { "@react-navigation/elements": "^2.7.0", "color": "^4.2.3" }, "peerDependencies": { "@react-navigation/native": "^7.1.18", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-JY9yQDQTv7avXqXdrToyn6ogcBqY2gTXg7C1J6OWZGz7QhlnPZQm375T4nYBWqVWsODVNeNagkCPptZGOxI1rg=="],
"expo-router/@react-navigation/native": ["@react-navigation/native@7.1.18", "", { "dependencies": { "@react-navigation/core": "^7.12.4", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-DZgd6860dxcq3YX7UzIXeBr6m3UgXvo9acxp5jiJyIZXdR00Br9JwVkO7e0bUeTA2d3Z8dsmtAR84Y86NnH64Q=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], "fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="],
@@ -3575,9 +3577,7 @@
"@sentry/bundler-plugin-core/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "@sentry/bundler-plugin-core/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"@sentry/nextjs/@sentry/react/@sentry/browser": ["@sentry/browser@10.21.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.21.0", "@sentry-internal/feedback": "10.21.0", "@sentry-internal/replay": "10.21.0", "@sentry-internal/replay-canvas": "10.21.0", "@sentry/core": "10.21.0" } }, "sha512-z/63bUFBQkTfJ5ElhWTYvomz+gZ1GsoH16v4/RGoPY5qZgYxcVO3fkp0opnu3gcbXS0ZW7TLRiHpqhvipDdP6g=="], "@sentry/nextjs/@sentry/react/@sentry/browser": ["@sentry/browser@10.22.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.22.0", "@sentry-internal/feedback": "10.22.0", "@sentry-internal/replay": "10.22.0", "@sentry-internal/replay-canvas": "10.22.0", "@sentry/core": "10.22.0" } }, "sha512-wD2XqN+yeBpQFfdPo6+wlKDMyyuDctVGzZWE4qTPntICKQuwMdAfeq5Ma89ad0Dw+bzG9UijGeyuJQlswF87Mw=="],
"@sentry/nextjs/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"@sentry/node/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@sentry/node/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
@@ -3667,6 +3667,10 @@
"expo-modules-autolinking/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "expo-modules-autolinking/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"expo-router/@react-navigation/bottom-tabs/@react-navigation/elements": ["@react-navigation/elements@2.7.0", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.18", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-lqlUUTqzKJrm3WYmiy901DSpa5wW8DWSmqNqWlRFWDVjx6SSjOUThQpdMnVXhydPtrTo74yVUPB27oe/jrvo4Q=="],
"expo-router/@react-navigation/native/@react-navigation/core": ["@react-navigation/core@7.12.4", "", { "dependencies": { "@react-navigation/routers": "^7.5.1", "escape-string-regexp": "^4.0.0", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-xLFho76FA7v500XID5z/8YfGTvjQPw7/fXsq4BIrVSqetNe/o/v+KAocEw4ots6kyv3XvSTyiWKh2g3pN6xZ9Q=="],
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
@@ -3809,11 +3813,11 @@
"@sentry/bundler-plugin-core/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], "@sentry/bundler-plugin-core/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/feedback": ["@sentry-internal/feedback@10.21.0", "", { "dependencies": { "@sentry/core": "10.21.0" } }, "sha512-6SnRR2FiW6TMwCE0PqbueHkkpeVnjOjz00R+/mX25Dp1U5BU5TzbXHzn9Y4wKnaD3Rzz4+nnzVkpHAOL3SppGw=="], "@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/feedback": ["@sentry-internal/feedback@10.22.0", "", { "dependencies": { "@sentry/core": "10.22.0" } }, "sha512-zXySOin/gGHPV+yKaHqjN9YZ7psEJwzLn8PzCLeo+4REzF1eQwbYZIgOxJFD32z8s3nZiABSWFM/n1CvVfMEsQ=="],
"@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/replay": ["@sentry-internal/replay@10.21.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.21.0", "@sentry/core": "10.21.0" } }, "sha512-5tfiKZJzZf9+Xk8SyvoC4ZEVLNmjBZZEaKhVyNo53CLWUWfWOqDc3DB9fj85i/yHFQ0ImdRnaPBc0CIeN00CcA=="], "@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/replay": ["@sentry-internal/replay@10.22.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.22.0", "@sentry/core": "10.22.0" } }, "sha512-JNE4kHAQSG4/V+J+Zog3vKBWgOe9H33ol/MEU1RuLM/4I+uLf4mTetwnS9ilpnnW/Z/gQYfA+R3CiMrZtqTivw=="],
"@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.21.0", "", { "dependencies": { "@sentry-internal/replay": "10.21.0", "@sentry/core": "10.21.0" } }, "sha512-TOLo5mAjJSOuJId8Po44d1hwJ5bIZDtRSoupWpYWqLw1tuUh1tc4vqID11ZXsw9pBzjVIK653BPDX/z/9+Um+Q=="], "@sentry/nextjs/@sentry/react/@sentry/browser/@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.22.0", "", { "dependencies": { "@sentry-internal/replay": "10.22.0", "@sentry/core": "10.22.0" } }, "sha512-DE4JNUskJg+O+wFq42W5gAa/99aD5k7TfGOwABxvnzFv8vkKA7pqXwPbFFPzypdKIkln+df7RmbnDwQRNg6/lA=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.44.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.44.1", "@typescript-eslint/types": "^8.44.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA=="], "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.44.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.44.1", "@typescript-eslint/types": "^8.44.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA=="],

View File

@@ -8,11 +8,6 @@
* @module * @module
*/ */
import type {
ApiFromModules,
FilterApi,
FunctionReference,
} from "convex/server";
import type * as auth from "../auth.js"; import type * as auth from "../auth.js";
import type * as crons from "../crons.js"; import type * as crons from "../crons.js";
import type * as custom_auth_index from "../custom/auth/index.js"; import type * as custom_auth_index from "../custom/auth/index.js";
@@ -23,6 +18,12 @@ import type * as files from "../files.js";
import type * as http from "../http.js"; import type * as http from "../http.js";
import type * as statuses from "../statuses.js"; import type * as statuses from "../statuses.js";
import type {
ApiFromModules,
FilterApi,
FunctionReference,
} from "convex/server";
/** /**
* A utility for referencing Convex functions in your app's API. * A utility for referencing Convex functions in your app's API.
* *
@@ -42,11 +43,15 @@ declare const fullApi: ApiFromModules<{
http: typeof http; http: typeof http;
statuses: typeof statuses; statuses: typeof statuses;
}>; }>;
declare const fullApiWithMounts: typeof fullApi;
export declare const api: FilterApi< export declare const api: FilterApi<
typeof fullApi, typeof fullApiWithMounts,
FunctionReference<any, "public"> FunctionReference<any, "public">
>; >;
export declare const internal: FilterApi< export declare const internal: FilterApi<
typeof fullApi, typeof fullApiWithMounts,
FunctionReference<any, "internal"> FunctionReference<any, "internal">
>; >;
export declare const components: {};

View File

@@ -8,7 +8,7 @@
* @module * @module
*/ */
import { anyApi } from "convex/server"; import { anyApi, componentsGeneric } from "convex/server";
/** /**
* A utility for referencing Convex functions in your app's API. * A utility for referencing Convex functions in your app's API.
@@ -20,3 +20,4 @@ import { anyApi } from "convex/server";
*/ */
export const api = anyApi; export const api = anyApi;
export const internal = anyApi; export const internal = anyApi;
export const components = componentsGeneric();

View File

@@ -10,6 +10,7 @@
import { import {
ActionBuilder, ActionBuilder,
AnyComponents,
HttpActionBuilder, HttpActionBuilder,
MutationBuilder, MutationBuilder,
QueryBuilder, QueryBuilder,
@@ -18,9 +19,15 @@ import {
GenericQueryCtx, GenericQueryCtx,
GenericDatabaseReader, GenericDatabaseReader,
GenericDatabaseWriter, GenericDatabaseWriter,
FunctionReference,
} from "convex/server"; } from "convex/server";
import type { DataModel } from "./dataModel.js"; import type { DataModel } from "./dataModel.js";
type GenericCtx =
| GenericActionCtx<DataModel>
| GenericMutationCtx<DataModel>
| GenericQueryCtx<DataModel>;
/** /**
* Define a query in this Convex app's public API. * Define a query in this Convex app's public API.
* *

View File

@@ -16,6 +16,7 @@ import {
internalActionGeneric, internalActionGeneric,
internalMutationGeneric, internalMutationGeneric,
internalQueryGeneric, internalQueryGeneric,
componentsGeneric,
} from "convex/server"; } from "convex/server";
/** /**

View File

@@ -1,7 +1,7 @@
// convex/crons.ts
import { cronJobs } from 'convex/server'; import { cronJobs } from 'convex/server';
import { api } from './_generated/api'; import { api } from './_generated/api';
// Cron order: Minute Hour DayOfMonth Month DayOfWeek
const crons = cronJobs(); const crons = cronJobs();
crons.cron( crons.cron(
@@ -13,9 +13,9 @@ crons.cron(
); );
crons.cron( crons.cron(
'End of shift (weekdays 5pm CT)',
// Run at 4:00 PM CST / 5:00 PM CDT // Run at 4:00 PM CST / 5:00 PM CDT
// Only on weekdays // Only on weekdays
'End of shift (weekdays 5pm CT)',
'0 22 * * 1-5', '0 22 * * 1-5',
api.statuses.endOfShiftUpdate, api.statuses.endOfShiftUpdate,
); );

View File

@@ -26,6 +26,7 @@ export default defineSchema({
message: v.string(), message: v.string(),
updatedAt: v.number(), updatedAt: v.number(),
updatedBy: v.optional(v.id('users')), updatedBy: v.optional(v.id('users')),
persistentStatus: v.optional(v.boolean()),
}) })
.index('by_user', ['userId']) .index('by_user', ['userId'])
.index('by_user_updatedAt', ['userId', 'updatedAt']), .index('by_user_updatedAt', ['userId', 'updatedAt']),

View File

@@ -24,6 +24,7 @@ type StatusRow = {
message: string; message: string;
updatedAt: number; updatedAt: number;
updatedBy: StatusRow['user'] | null; updatedBy: StatusRow['user'] | null;
persistentStatus: boolean;
} | null; } | null;
}; };
@@ -56,6 +57,7 @@ export const create = mutation({
message: v.string(), message: v.string(),
userId: v.optional(v.id('users')), userId: v.optional(v.id('users')),
updatedBy: v.optional(v.id('users')), updatedBy: v.optional(v.id('users')),
persistentStatus: v.optional(v.boolean()),
}, },
handler: async (ctx, args) => { handler: async (ctx, args) => {
const authUserId: Id<'users'> | null = await getAuthUserId(ctx); const authUserId: Id<'users'> | null = await getAuthUserId(ctx);
@@ -68,6 +70,7 @@ export const create = mutation({
} }
const userId = args.userId ?? authUserId!; const userId = args.userId ?? authUserId!;
const updatedBy = args.updatedBy ?? authUserId; const updatedBy = args.updatedBy ?? authUserId;
const persistentStatus = args.persistentStatus ?? false;
await ensureUser(ctx, userId); await ensureUser(ctx, userId);
let statusId: Id<'statuses'>; let statusId: Id<'statuses'>;
if (updatedBy) { if (updatedBy) {
@@ -77,12 +80,14 @@ export const create = mutation({
userId, userId,
updatedBy, updatedBy,
updatedAt: Date.now(), updatedAt: Date.now(),
persistentStatus,
}); });
} else { } else {
statusId = await ctx.db.insert('statuses', { statusId = await ctx.db.insert('statuses', {
message, message,
userId, userId,
updatedAt: Date.now(), updatedAt: Date.now(),
persistentStatus,
}); });
} }
await ctx.db.patch(userId, { currentStatusId: statusId }); await ctx.db.patch(userId, { currentStatusId: statusId });
@@ -95,6 +100,7 @@ export const bulkCreate = mutation({
message: v.string(), message: v.string(),
userIds: v.array(v.id('users')), userIds: v.array(v.id('users')),
updatedBy: v.optional(v.id('users')), updatedBy: v.optional(v.id('users')),
persistentStatus: v.optional(v.boolean()),
}, },
handler: async (ctx, args) => { handler: async (ctx, args) => {
const authUserId = await getAuthUserId(ctx); const authUserId = await getAuthUserId(ctx);
@@ -103,6 +109,7 @@ export const bulkCreate = mutation({
if (args.userIds.length === 0) return { statusIds: [] }; if (args.userIds.length === 0) return { statusIds: [] };
const updatedBy = args.updatedBy ?? authUserId; const updatedBy = args.updatedBy ?? authUserId;
const persistentStatus = args.persistentStatus ?? false;
await ensureUser(ctx, updatedBy); await ensureUser(ctx, updatedBy);
const message = args.message.trim(); const message = args.message.trim();
@@ -120,6 +127,7 @@ export const bulkCreate = mutation({
userId, userId,
updatedBy, updatedBy,
updatedAt: now, updatedAt: now,
persistentStatus,
}); });
await ctx.db.patch(userId, { currentStatusId: statusId }); await ctx.db.patch(userId, { currentStatusId: statusId });
statusIds.push(statusId); statusIds.push(statusId);
@@ -130,10 +138,14 @@ export const bulkCreate = mutation({
}); });
export const updateAllStatuses = mutation({ export const updateAllStatuses = mutation({
args: { message: v.string() }, args: {
message: v.string(),
persistentStatus: v.optional(v.boolean())
},
handler: async (ctx, args) => { handler: async (ctx, args) => {
const users = await ctx.db.query('users').collect(); const users = await ctx.db.query('users').collect();
const message = args.message.trim(); const message = args.message.trim();
const persistentStatus = args.persistentStatus ?? false;
if (message.length === 0) { if (message.length === 0) {
throw new ConvexError('Message cannot be empty.'); throw new ConvexError('Message cannot be empty.');
} }
@@ -142,15 +154,20 @@ export const updateAllStatuses = mutation({
const now = Date.now(); const now = Date.now();
for (const user of users) { for (const user of users) {
const curStatus = await ctx.runQuery(api.statuses.getCurrentForUser, {
userId: user._id,
});
if (!curStatus?.persistentStatus) {
const statusId = await ctx.db.insert('statuses', { const statusId = await ctx.db.insert('statuses', {
message, message,
userId: user._id, userId: user._id,
updatedAt: now, updatedAt: now,
persistentStatus,
}); });
await ctx.db.patch(user._id, { currentStatusId: statusId }); await ctx.db.patch(user._id, { currentStatusId: statusId });
statusIds.push(statusId); statusIds.push(statusId);
} }
}
return { statusIds }; return { statusIds };
}, },
}); });
@@ -161,6 +178,12 @@ export const createLunchStatus = mutation({
const authUserId = await getAuthUserId(ctx); const authUserId = await getAuthUserId(ctx);
const lunchUserId = args.userId ?? authUserId const lunchUserId = args.userId ?? authUserId
if (!lunchUserId) throw new ConvexError('Not authenticated.'); if (!lunchUserId) throw new ConvexError('Not authenticated.');
const curStatus = await ctx.runQuery(api.statuses.getCurrentForUser, {
userId: lunchUserId,
});
if (curStatus?.persistentStatus) {
return { success: false, error: 'Current status is persistent.'};
}
await ctx.runMutation(api.statuses.create, { await ctx.runMutation(api.statuses.create, {
message: 'At lunch', message: 'At lunch',
userId: lunchUserId, userId: lunchUserId,
@@ -179,6 +202,12 @@ export const backFromLunchStatus = mutation({
const authUserId = await getAuthUserId(ctx); const authUserId = await getAuthUserId(ctx);
const lunchUserId = args.userId ?? authUserId const lunchUserId = args.userId ?? authUserId
if (!lunchUserId) throw new ConvexError('Not authenticated.'); if (!lunchUserId) throw new ConvexError('Not authenticated.');
const curStatus = await ctx.runQuery(api.statuses.getCurrentForUser, {
userId: lunchUserId,
});
if (curStatus?.persistentStatus) {
return { success: false, error: 'Current status is persistent.'};
}
const user = await ensureUser(ctx, lunchUserId); const user = await ensureUser(ctx, lunchUserId);
if (!user.currentStatusId) throw new ConvexError('User has no current status.'); if (!user.currentStatusId) throw new ConvexError('User has no current status.');
const currentStatus = await ctx.db.get(user.currentStatusId); const currentStatus = await ctx.db.get(user.currentStatusId);
@@ -253,6 +282,7 @@ export const getCurrentForAll = query({
message: curStatus.message, message: curStatus.message,
updatedAt: curStatus.updatedAt, updatedAt: curStatus.updatedAt,
updatedBy: updatedByUser, updatedBy: updatedByUser,
persistentStatus: curStatus.persistentStatus ?? false,
} }
: null; : null;
return { return {
@@ -318,6 +348,7 @@ export const listHistory = query({
message: s.message, message: s.message,
updatedAt: s.updatedAt, updatedAt: s.updatedAt,
updatedBy, updatedBy,
persistentStatus: s.persistentStatus ?? false,
}, },
}); });
} }