Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/actions/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use server'
'use server'

import { getUserProfileServer, checkAndResetUsageServer } from '@/lib/usage-tracking-server'
import { buildProfileUsageSummary } from '@/lib/profile-usage'
Expand Down Expand Up @@ -209,3 +209,4 @@ export async function fetchHistoryPageData(userId: string, page: number = 1, pag
return { sessions: [], hasMore: false }
}
}

7 changes: 5 additions & 2 deletions app/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use client'
'use client'

import { useCallback, useEffect, useState } from 'react'
import Link from 'next/link'
Expand Down Expand Up @@ -378,7 +378,7 @@ export default function ProfilePage() {
recentSessions.map((session) => (
<Link key={session.session_id} href={`/new/${session.session_id}`} className="block rounded-[20px] border border-tera-border bg-white/[0.03] px-4 py-4 transition hover:border-white/16 hover:bg-white/[0.05]">
<p className="truncate text-sm font-medium text-tera-primary">{session.title || 'Untitled session'}</p>
<p className="mt-1 text-[0.68rem] uppercase tracking-[0.22em] text-tera-secondary">{session.tool || 'Universal'} {new Date(session.created_at).toLocaleDateString()}</p>
<p className="mt-1 text-[0.68rem] uppercase tracking-[0.22em] text-tera-secondary">{session.tool || 'Universal'} · {new Date(session.created_at).toLocaleDateString()}</p>
</Link>
))
) : (
Expand All @@ -390,3 +390,6 @@ export default function ProfilePage() {
</div>
)
}



41 changes: 21 additions & 20 deletions components/PromptShell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"use client"
"use client"

import React, { ChangeEvent, useCallback, useEffect, useRef, useState, useTransition } from 'react'
import Image from 'next/image'
Expand Down Expand Up @@ -573,7 +573,7 @@ export default function PromptShell({

// Check if this request is still valid (hasn't been stopped or superseded)
if (currentRequestId !== requestIdRef.current) {
console.log('🛑 Request cancelled/superseded, ignoring response')
console.log('🛑 Request cancelled/superseded, ignoring response')
return
}

Expand Down Expand Up @@ -720,7 +720,7 @@ export default function PromptShell({
prompt: messageToSend,
attachments: [...pendingAttachments]
}
console.log('🔴 SAVING to localStorage:', messageData)
console.log('🔴 SAVING to localStorage:', messageData)
localStorage.setItem('tera_queued_message', JSON.stringify(messageData))
}
setAttachmentMessage('Sign in to send your message. It will be posted automatically once you authenticate.')
Expand All @@ -732,7 +732,7 @@ export default function PromptShell({
prompt: messageToSend,
attachments: [...pendingAttachments]
})
setAttachmentMessage('Hang tight—finalizing your account before sending.')
setAttachmentMessage('Hang tight—finalizing your account before sending.')
return
}

Expand All @@ -746,37 +746,37 @@ export default function PromptShell({

useEffect(() => {
// Always check for persisted message on mount
console.log('🟢 MOUNT EFFECT: Checking localStorage...')
console.log('🟢 MOUNT EFFECT: Checking localStorage...')
if (typeof window !== 'undefined' && !queuedMessage) {
const savedMessage = localStorage.getItem('tera_queued_message')
console.log('🟢 localStorage value:', savedMessage)
console.log('🟢 localStorage value:', savedMessage)
if (savedMessage) {
try {
console.log('🟢 Found queued message, parsing...')
console.log('🟢 Found queued message, parsing...')
const parsed = JSON.parse(savedMessage)
console.log('🟢 Parsed message:', parsed)
console.log('🟢 Parsed message:', parsed)
setQueuedMessage(parsed)
console.log('🟢 Set queuedMessage state')
console.log('🟢 Set queuedMessage state')
} catch (e) {
console.error('🔴 Failed to parse queued message', e)
console.error('🔴 Failed to parse queued message', e)
localStorage.removeItem('tera_queued_message')
}
} else {
console.log('🟢 No saved message found in localStorage')
console.log('🟢 No saved message found in localStorage')
}
} else {
console.log('🟢 Skipping restore (window undefined or queuedMessage already set)')
console.log('🟢 Skipping restore (window undefined or queuedMessage already set)')
}
}, []) // Run once on mount

useEffect(() => {
console.log('🔵 PROCESS EFFECT: userReady=', userReady, 'queuedMessage=', queuedMessage)
console.log('🔵 PROCESS EFFECT: userReady=', userReady, 'queuedMessage=', queuedMessage)
if (userReady && queuedMessage) {
console.log('🔵 Processing queued message:', queuedMessage)
console.log('🔵 Processing queued message:', queuedMessage)
processMessage(queuedMessage.prompt, queuedMessage.attachments)

// Clean up
console.log('🔵 Cleaning up localStorage and queuedMessage state')
console.log('🔵 Cleaning up localStorage and queuedMessage state')
localStorage.removeItem('tera_queued_message')
setQueuedMessage(null)
}
Expand Down Expand Up @@ -873,7 +873,7 @@ export default function PromptShell({
if (data.plan) {
setCurrentUserPlan(data.plan)
}
console.log(`🔍 Web Search Status: ${data.remaining}/${data.total} (${data.plan?.toUpperCase()})`)
console.log(`🔍 Web Search Status: ${data.remaining}/${data.total} (${data.plan?.toUpperCase()})`)
}
} catch (err) {
console.warn('Failed to fetch web search status:', err)
Expand Down Expand Up @@ -992,7 +992,7 @@ export default function PromptShell({
<div className="mt-3 flex flex-wrap gap-2">
{entry.userMessage.attachments.map((att, idx) => (
<div key={idx} className="flex items-center gap-2 rounded-lg bg-black/5 px-3 py-2 text-xs">
<span>{att.type === 'image' ? '🖼️' : '📄'}</span>
<span>{att.type === 'image' ? '🖼️' : '📄'}</span>
<span className="truncate max-w-[150px]">{att.name}</span>
</div>
))}
Expand All @@ -1002,7 +1002,7 @@ export default function PromptShell({
{/* Timestamp and checkmarks */}
<div className="flex items-center gap-1.5 px-2 text-xs text-tera-secondary">
<span>{formatTimestamp(entry.userMessage.timestamp)}</span>
<span className="text-tera-secondary/60">✓✓</span>
<span className="text-tera-secondary/60">✓✓</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -1179,7 +1179,7 @@ export default function PromptShell({
className="absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full border border-white/10 bg-black/70 text-white opacity-0 transition-all group-hover:opacity-100 hover:bg-red-500"
title="Remove"
>
×
×
</button>
</div>
))}
Expand Down Expand Up @@ -1367,7 +1367,7 @@ export default function PromptShell({
onClick={() => setSearchHistoryOpen(false)}
className="absolute -top-10 right-0 text-white/80 hover:text-white"
>
Close ×
Close ×
</button>
<SearchHistoryRenderer
userId={user.id}
Expand Down Expand Up @@ -1426,3 +1426,4 @@ export default function PromptShell({




3 changes: 2 additions & 1 deletion components/UsageMetricCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use client'
'use client'

import type { UsageMetricSummary } from '@/lib/profile-usage'

Expand Down Expand Up @@ -67,3 +67,4 @@ export default function UsageMetricCard({
</div>
)
}

3 changes: 2 additions & 1 deletion lib/profile-usage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getPlanConfig, type PlanType } from './plan-config'
import { getPlanConfig, type PlanType } from './plan-config'

export type UsageLimit = number | 'unlimited'

Expand Down Expand Up @@ -79,3 +79,4 @@ export function buildProfileUsageSummary(source: ProfileUsageSource): ProfileUsa
),
}
}

3 changes: 2 additions & 1 deletion lib/usage-events.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export const TERA_USAGE_REFRESH_EVENT = 'tera:usage-refresh'
export const TERA_USAGE_REFRESH_EVENT = 'tera:usage-refresh'

export function dispatchUsageRefresh(reason: 'messages' | 'uploads' | 'web-search' | 'profile') {
if (typeof window === 'undefined') return

window.dispatchEvent(new CustomEvent(TERA_USAGE_REFRESH_EVENT, { detail: { reason, at: Date.now() } }))
}

3 changes: 2 additions & 1 deletion lib/web-search-usage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/**
* Web Search Usage Tracking
* Tracks and limits web searches based on subscription plan:
* - Free: 5/month
Expand Down Expand Up @@ -218,3 +218,4 @@ export function getWebSearchLimitMessage(remaining: number, total: number): stri
export const WEB_SEARCH_LIMITS = MONTHLY_WEB_SEARCH_LIMITS
export const getDefaultLimit = (plan: PlanType = 'free') => MONTHLY_WEB_SEARCH_LIMITS[plan]