Skip to content

Commit c5a66ac

Browse files
committed
Cleanup
1 parent 858325f commit c5a66ac

6 files changed

Lines changed: 91 additions & 36 deletions

File tree

app/api/user-settings/route.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,28 +58,31 @@ export async function PATCH(req: NextRequest) {
5858
const body = await req.json()
5959
const { model } = body
6060
if (!model) return NextResponse.json({ error: 'Model required' }, { status: 400 })
61-
// Get current count and last reset
61+
const today = new Date().toISOString().slice(0, 10)
62+
// Atomic update: reset if needed, then decrement if premium
6263
const { data, error: userError } = await supabase
6364
.from('users')
6465
.select('daily_query_count, last_query_reset')
6566
.eq('id', user.id)
6667
.single()
6768
if (userError) return NextResponse.json({ error: userError.message }, { status: 500 })
68-
const today = new Date().toISOString().slice(0, 10)
69-
let daily_query_count = data?.daily_query_count ?? 50
70-
const last_query_reset = data?.last_query_reset
71-
// Reset if last_query_reset is not today
69+
let { daily_query_count, last_query_reset } = data ?? {}
7270
if (last_query_reset !== today) {
7371
daily_query_count = 50
74-
await supabase.from('users').update({ daily_query_count, last_query_reset: today }).eq('id', user.id)
72+
last_query_reset = today
7573
}
76-
// Only decrement if not free model
74+
// Only decrement for premium models
7775
if (!/free/i.test(model)) {
7876
if (daily_query_count <= 0) {
79-
return NextResponse.json({ error: 'Query limit reached', dailyQueryCount: 0 }, { status: 403 })
77+
return NextResponse.json({ error: 'Query limit reached' }, { status: 403 })
8078
}
81-
daily_query_count -= 1
82-
await supabase.from('users').update({ daily_query_count }).eq('id', user.id)
79+
daily_query_count--
8380
}
81+
// Single update
82+
const { error: updateError } = await supabase
83+
.from('users')
84+
.update({ daily_query_count, last_query_reset })
85+
.eq('id', user.id)
86+
if (updateError) return NextResponse.json({ error: updateError.message }, { status: 500 })
8487
return NextResponse.json({ dailyQueryCount: daily_query_count })
8588
}

components/chat/chat-input.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ const ChatInput = React.memo(function ChatInput({ onOpenSearch, defaultModel }:
463463
</Tooltip.Content>
464464
</Tooltip.Portal>
465465
</Tooltip.Root>
466-
{[Search, Globe, ImageIcon, MoreHorizontal].map((Icon, i) => (
466+
{[Search].map((Icon, i) => (
467467
<Tooltip.Root key={i} delayDuration={200}>
468468
<Tooltip.Trigger asChild>
469469
<Button
@@ -487,7 +487,7 @@ const ChatInput = React.memo(function ChatInput({ onOpenSearch, defaultModel }:
487487
fontFamily: "var(--font-sans)",
488488
}}
489489
>
490-
{["Search", "Web search", "Create image", "More"][i]}
490+
{["Search"][i]}
491491
<Tooltip.Arrow className="fill-[var(--popover)]" />
492492
</Tooltip.Content>
493493
</Tooltip.Portal>

components/chat/file-upload.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Input } from '@/components/ui/input'
66
const MAX_SIZE_MB = 10
77
const ALLOWED_TYPES = [
88
'image/png', 'image/jpeg', 'image/webp', 'application/pdf',
9-
'text/plain', 'application/zip', 'application/json',
9+
'text/plain', 'application/zip', 'application/json', 'text/markdown'
1010
]
1111

1212
export type FileUploadProps = {

components/chat/sidebar-footer.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from 'react'
1+
import { useEffect, useState } from 'react'
22
import useSWR from 'swr'
33
import { usePremiumQueryCountStore } from '@/hooks/use-premium-query-count-store'
44

@@ -7,15 +7,32 @@ export default function SidebarFooter() {
77
const { data: userSettings } = useSWR('/api/user-settings', fetcher, { revalidateOnFocus: false })
88
const count = usePremiumQueryCountStore(s => s.count)
99
const isUnlimited = usePremiumQueryCountStore(s => s.isUnlimited)
10-
const set = usePremiumQueryCountStore(s => s.set)
10+
const syncFromDb = usePremiumQueryCountStore(s => s.syncFromDb)
11+
const [hydrated, setHydrated] = useState(false)
12+
13+
useEffect(() => {
14+
setHydrated(true)
15+
}, [])
16+
1117
useEffect(() => {
12-
if (userSettings) set(userSettings.dailyQueryCount ?? 50, !!userSettings.hasTogetherApiKey)
13-
}, [userSettings, set])
18+
if (userSettings && typeof userSettings.dailyQueryCount === 'number') {
19+
syncFromDb(userSettings.dailyQueryCount, !!userSettings.hasTogetherApiKey)
20+
}
21+
}, [userSettings, syncFromDb])
22+
23+
if (!hydrated) return null
24+
1425
return (
1526
<div className="flex items-center justify-center p-3 border-t border-[#2a2b32] text-xs text-[#b4bcd0] mt-auto w-full">
16-
<span className="px-3 py-1 rounded-full bg-[#23272f] border border-[#353740] text-[#b4bcd0] text-sm font-medium" title="Premium queries available today">
17-
Daily premium queries: {isUnlimited ? 'Unlimited' : `${count}/50`}
18-
</span>
27+
{typeof count === 'number' ? (
28+
<span className="px-3 py-1 rounded-full bg-[#23272f] border border-[#353740] text-[#b4bcd0] text-sm font-medium" title="Premium queries available today">
29+
Premium queries: {isUnlimited ? 'Unlimited' : `${count}/50`}
30+
</span>
31+
) : (
32+
<span className="px-3 py-1 rounded-full bg-[#23272f] border border-[#353740] text-[#b4bcd0] text-sm font-medium opacity-60 animate-pulse" title="Loading premium queries...">
33+
Premium queries: ...
34+
</span>
35+
)}
1936
</div>
2037
)
2138
}
Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,53 @@
11
import { create } from 'zustand'
22

33
interface PremiumQueryCountState {
4-
count: number
4+
count: number | null
55
isUnlimited: boolean
66
set: (count: number, isUnlimited: boolean) => void
77
decrement: () => void
88
reset: () => void
9+
syncFromDb: (count: number, isUnlimited: boolean) => void
910
}
1011

11-
export const usePremiumQueryCountStore = create<PremiumQueryCountState>((set) => ({
12-
count: 50,
13-
isUnlimited: false,
14-
set: (count, isUnlimited) => set({ count, isUnlimited }),
15-
decrement: () => set((s) => s.isUnlimited ? s : { ...s, count: Math.max(0, s.count - 1) }),
16-
reset: () => set({ count: 50, isUnlimited: false }),
17-
}))
12+
function persist(count: number | null, isUnlimited: boolean) {
13+
if (typeof window !== 'undefined') {
14+
if (count !== null) localStorage.setItem('premiumQueryCount', String(count))
15+
localStorage.setItem('isUnlimited', String(isUnlimited))
16+
}
17+
}
18+
19+
export const usePremiumQueryCountStore = create<PremiumQueryCountState>((set, get) => {
20+
// Hydrate from localStorage
21+
let count: number | null = 50
22+
let isUnlimited = false
23+
if (typeof window !== 'undefined') {
24+
const stored = localStorage.getItem('premiumQueryCount')
25+
const unlimited = localStorage.getItem('isUnlimited')
26+
if (stored) count = Number(stored)
27+
if (unlimited) isUnlimited = unlimited === 'true'
28+
}
29+
return {
30+
count,
31+
isUnlimited,
32+
set: (count, isUnlimited) => {
33+
persist(count, isUnlimited)
34+
set({ count, isUnlimited })
35+
},
36+
decrement: () => {
37+
const { count, isUnlimited } = get()
38+
if (!isUnlimited && count !== null) {
39+
const newCount = Math.max(0, count - 1)
40+
persist(newCount, isUnlimited)
41+
set({ count: newCount })
42+
}
43+
},
44+
reset: () => {
45+
persist(50, false)
46+
set({ count: 50, isUnlimited: false })
47+
},
48+
syncFromDb: (count, isUnlimited) => {
49+
persist(count, isUnlimited)
50+
set({ count, isUnlimited })
51+
},
52+
}
53+
})

knowledge_base/tasks.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,13 @@
110110

111111
## Phase 6: User Settings and Preferences
112112

113-
- [ ] Create settings page
114-
- [ ] Allow user to store their together.ai api key and use it for requests
115-
- [ ] Force users to use their own API key for model requests that are not free (we know free ones as they have "free" in the name)
116-
- [ ] Add message history preferences
117-
- [ ] Implement settings persistence
118-
- [ ] Add user profile management [name, email, account deletion]
119-
120-
## Phase 7: Performance and Polish
113+
- [x] Create settings page
114+
- [x] Allow user to store their together.ai api key and use it for requests
115+
- [x] Force users to use their own API key for model requests that are not free (we know free ones as they have "free" in the name)
116+
- [x] Implement settings persistence
117+
- [x] Add user profile management [name, email, account deletion]
118+
119+
## Phase 7: Performance and Polish (NEXT)
121120

122121
- [ ] Implement proper error handling
123122
- [ ] Add loading states and skeletons

0 commit comments

Comments
 (0)