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": {
"@expo/vector-icons": "^15.0.3",
"@react-navigation/bottom-tabs": "^7.5.0",
"@react-navigation/elements": "^2.7.0",
"@react-navigation/native": "^7.1.18",
"@react-navigation/bottom-tabs": "^7.6.0",
"@react-navigation/elements": "^2.7.1",
"@react-navigation/native": "^7.1.19",
"@sentry/react-native": "^7.4.0",
"expo": "~54.0.19",
"expo": "~54.0.20",
"expo-apple-authentication": "~8.0.7",
"expo-constants": "~18.0.10",
"expo-font": "~14.0.9",

View File

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

View File

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

View File

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