Skip to content

Commit d6214b8

Browse files
committed
resolved final tasks
1 parent cff2965 commit d6214b8

File tree

8 files changed

+128
-64
lines changed

8 files changed

+128
-64
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use client"
2+
3+
import { useEffect, useState } from "react"
4+
import { ClockFading } from "lucide-react"
5+
import { getLastLoginMethod, getLoginMethodDisplayName, type LoginMethod } from "@/lib/lastLoginMethod"
6+
7+
export function LastUsedMethod() {
8+
const [lastMethod, setLastMethod] = useState<LoginMethod | null>(null)
9+
10+
useEffect(() => {
11+
// Get last login method from localStorage
12+
const method = getLastLoginMethod()
13+
setLastMethod(method)
14+
}, [])
15+
16+
if (!lastMethod) {
17+
return null
18+
}
19+
20+
const displayName = getLoginMethodDisplayName(lastMethod)
21+
22+
return (
23+
<div className="flex items-center gap-2 px-3 py-2 bg-muted rounded-full border border-muted-foreground/60 border-dashed w-fit">
24+
<ClockFading className="w-4 h-4 text-muted-foreground" />
25+
<span className="text-sm text-muted-foreground">
26+
Last used:
27+
</span>
28+
<div className="flex items-center gap-1.5">
29+
<span className="text-sm font-medium text-foreground">
30+
{displayName}
31+
</span>
32+
</div>
33+
</div>
34+
)
35+
}

src/components/keywords/keyword-analysis-results.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export function KeywordAnalysisResults({
272272
);
273273

274274
try {
275-
if (subscription?.price_id === null && monitoredKeywords.length >= 1) {
275+
if (subscription?.price_id === null && monitoredKeywords.length >= 1 && subscription.payg_credits === 0) {
276276
toast.error(
277277
"You have reached the limit of 1 monitored keyword. Please upgrade to a paid plan to monitor more keywords."
278278
);
@@ -326,7 +326,7 @@ export function KeywordAnalysisResults({
326326
};
327327

328328
const openScheduleModal = (keyword: KeywordData) => {
329-
if (subscription?.price_id === null && monitoredKeywords.length >= 1) {
329+
if (subscription?.price_id === null && monitoredKeywords.length >= 1 && subscription.payg_credits === 0) {
330330
toast.error(
331331
"You have reached the limit of 1 monitored keyword. Please upgrade to a paid plan to monitor more keywords."
332332
);

src/components/login-form.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useAuth } from "@/contexts/AuthContext"
1010
import { Button } from "@/components/ui/button"
1111
import { Input } from "@/components/ui/input"
1212
import { Label } from "@/components/ui/label"
13+
import { LastUsedMethod } from "@/components/auth/LastUsedMethod"
1314

1415
export function LoginForm({
1516
className,
@@ -77,6 +78,7 @@ export function LoginForm({
7778
</Link>
7879
</div>
7980
</div>
81+
<LastUsedMethod />
8082
<div className="flex flex-col gap-4">
8183
{error && (
8284
<div className="text-destructive text-sm">{error}</div>

src/components/monitoring/steps-tab-content.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ export function StepsTabContent({
337337
);
338338

339339
try {
340-
if (subscription?.price_id === null && monitoredKeywords.length >= 1) {
340+
if (subscription?.price_id === null && monitoredKeywords.length >= 1 && subscription.payg_credits === 0) {
341341
toast.error(
342342
"You have reached the limit of 1 monitored keyword. Please upgrade to a paid plan to monitor more keywords."
343343
);
@@ -385,7 +385,7 @@ export function StepsTabContent({
385385
};
386386

387387
const openScheduleModal = (keyword: KeywordData) => {
388-
if (subscription?.price_id === null && monitoredKeywords.length >= 1) {
388+
if (subscription?.price_id === null && monitoredKeywords.length >= 1 && subscription.payg_credits === 0) {
389389
toast.error(
390390
"You have reached the limit of 1 monitored keyword. Please upgrade to a paid plan to monitor more keywords."
391391
);

src/components/signup-form.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Button } from "@/components/ui/button"
1313
import { Input } from "@/components/ui/input"
1414
import { Label } from "@/components/ui/label"
1515
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
16+
import { LastUsedMethod } from "@/components/auth/LastUsedMethod"
1617

1718
export function SignupForm({
1819
className,
@@ -108,6 +109,7 @@ export function SignupForm({
108109
</Link>
109110
</div>
110111
</div>
112+
<LastUsedMethod />
111113
<div className="flex flex-col gap-4">
112114
{error && (
113115
<div className="text-destructive text-sm">{error}</div>

src/components/ui/ai-chat.tsx

Lines changed: 39 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,6 @@ import { supabase } from "@/lib/supabase";
5454
import { Checkbox } from "@/components/ui/checkbox";
5555
import { Badge } from "@/components/ui/badge";
5656
import { Separator } from "@/components/ui/separator";
57-
import {
58-
Dialog,
59-
DialogContent,
60-
DialogDescription,
61-
DialogHeader,
62-
DialogTitle,
63-
} from "@/components/ui/dialog";
6457
import {
6558
Claude,
6659
DeepSeek,
@@ -173,9 +166,7 @@ export function AIChatInterface({
173166
const [mode, setMode] = useState<AnalysisMode>("Explorer");
174167
const [loading, setLoading] = useState(false);
175168
const [isAnalyzing, setIsAnalyzing] = useState(false);
176-
const [isMonitoringMode, setIsMonitoringMode] = useState(
177-
true
178-
);
169+
const [isMonitoringMode, setIsMonitoringMode] = useState(true);
179170
const [attachedBrand, setAttachedBrand] = useState<Brand | null>(
180171
attachedBrandId
181172
? ({
@@ -368,9 +359,14 @@ export function AIChatInterface({
368359
const checkInactivity = () => {
369360
const now = Date.now();
370361
const timeSinceLastTyping = now - lastTypingTime;
371-
362+
372363
// Show modal if user hasn't typed for 10 seconds and input is empty
373-
if (timeSinceLastTyping >= 40000 && !value.trim() && !showInactivityModal && !isAnalyzing) {
364+
if (
365+
timeSinceLastTyping >= 40000 &&
366+
!value.trim() &&
367+
!showInactivityModal &&
368+
!isAnalyzing
369+
) {
374370
setShowInactivityModal(true);
375371
}
376372
};
@@ -949,7 +945,8 @@ export function AIChatInterface({
949945
<div className="space-y-4 mt-4">
950946
<div className="flex items-center justify-between">
951947
<h4 className="font-medium text-sm text-neutral-600 dark:text-white">
952-
AI Models for {modes.find((item) => item.key === mode)?.label}
948+
AI Models for{" "}
949+
{modes.find((item) => item.key === mode)?.label}
953950
</h4>
954951
<Badge
955952
variant="secondary"
@@ -1244,9 +1241,9 @@ export function AIChatInterface({
12441241
Voyager Mode
12451242
</h4>
12461243
<p className="text-sm text-neutral-500 dark:text-neutral-400 mt-1">
1247-
Leverages Llama 4 Maverick, DeepSeek v3, Grok 4, and many more top LLMs
1248-
to create in-depth brand ranking and keyword analysis.
1249-
No native search support.
1244+
Leverages Llama 4 Maverick, DeepSeek v3, Grok 4, and many
1245+
more top LLMs to create in-depth brand ranking and keyword
1246+
analysis. No native search support.
12501247
</p>
12511248
</div>
12521249
</div>
@@ -1268,20 +1265,34 @@ export function AIChatInterface({
12681265
)}
12691266

12701267
<div className="pt-2 border-t border-[#e2e2e2]/50 dark:border-neutral-800">
1271-
{/* <div className="flex items-start gap-3 mb-3">
1272-
<Zap className="w-4 h-4 text-purple-500 mt-0.5" />
1273-
<div>
1274-
<h4 className="font-medium text-sm text-neutral-700 dark:text-foreground">
1275-
Credit System
1268+
<div className="flex flex-col items-start gap-3 mb-3">
1269+
<div className="flex items-center gap-2">
1270+
<Zap className="w-4 h-4 text-purple-500" />
1271+
<h4 className="text-lg font-bold text-neutral-700 dark:text-foreground">
1272+
Not sure what to search and monitor?
12761273
</h4>
1277-
<p className="text-sm text-neutral-500 dark:text-neutral-400 mt-1">
1278-
Select specific AI models to optimize your credit usage. You
1279-
can choose individual models or use all available models for
1280-
comprehensive analysis. Google Search is always included at
1281-
no extra cost.
1274+
</div>
1275+
<div className="flex">
1276+
<p className=" text-neutral-500 dark:text-neutral-400 text-sm mt-2">
1277+
Let&apos;s give you{" "}
1278+
<span className="font-black text-primary">50 Prompts</span>{" "}
1279+
with monthly demand, trends, intent and cpc
12821280
</p>
1281+
<Button
1282+
variant="link"
1283+
onClick={() => {
1284+
toastSonner.success("Redirecting to keywords...");
1285+
setTimeout(() => {
1286+
router.push("/dashboard/keywords");
1287+
}, 1000);
1288+
}}
1289+
className="group transition-all duration-300 text-white font-medium text-sm"
1290+
>
1291+
Let&apos;s Go
1292+
<ChevronRight className="w-4 h-4 group-hover:translate-x-1 transition-all duration-300" />
1293+
</Button>
12831294
</div>
1284-
</div> */}
1295+
</div>
12851296
<p className="text-xs text-muted-foreground/30 dark:text-neutral-500">
12861297
{isMonitoringMode
12871298
? "Monitored queries run automatically with your selected models. View their status and results in the Monitoring tab."
@@ -1291,39 +1302,7 @@ export function AIChatInterface({
12911302
</div>
12921303
</div>
12931304
</div>
1294-
1295-
{/* Inactivity Modal */}
1296-
<Dialog open={showInactivityModal} onOpenChange={() => {
1297-
setShowInactivityModal(false);
1298-
setLastTypingTime(Date.now());
1299-
}}>
1300-
<DialogContent className="sm:max-w-xl p-12 bg-gradient-to-b from-background to-blue-600 rounded-2xl outline-2 outline-blue-600">
1301-
<DialogHeader>
1302-
<DialogTitle className="text-center text-3xl font-bold">
1303-
Not sure what to search and monitor?
1304-
</DialogTitle>
1305-
<DialogDescription className="text-center text-white text-base mt-2">
1306-
Let&apos;s give you <span className="font-black text-primary">50 Prompts</span> with monthly demand, trends, intent and cpc
1307-
</DialogDescription>
1308-
</DialogHeader>
1309-
<div className="flex justify-center mt-6">
1310-
<Button
1311-
onClick={() => {
1312-
setShowInactivityModal(false);
1313-
toastSonner.success("Redirecting to keywords...")
1314-
setTimeout(() => {
1315-
router.push("/dashboard/keywords")
1316-
}, 1000)
1317-
}}
1318-
className="w-full rounded-full sm:w-auto h-14 !px-10 bg-gradient-to-b from-blue-600 to-background/50 hover:bg-blue-600 transition-all duration-300 text-primary-foreground font-bold"
1319-
>
1320-
Let&apos;s Go
1321-
<ChevronRight className="w-4 h-4" />
1322-
</Button>
1323-
</div>
1324-
</DialogContent>
1325-
</Dialog>
1326-
1305+
13271306
<AttachBrandModal
13281307
showBrandModal={openModal}
13291308
setShowBrandModal={setOpenModal}

src/contexts/AuthContext.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { User, Session } from '@supabase/supabase-js'
1010
import { supabase } from '@/lib/supabase'
1111
import { toast } from '@/components/ui/use-toast'
1212
import { UserSubscription } from '@/hooks/useAuth'
13+
import { setLastLoginMethod } from '@/lib/lastLoginMethod'
1314
import Stripe from 'stripe'
1415

1516
// Simple type for auth context
@@ -154,6 +155,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
154155
if(data){
155156
setUser(data.user);
156157
setSession(data.session)
158+
// Store login method for "last used" feature
159+
setLastLoginMethod('password')
160+
157161
const { data: subscriptionData } = await supabase
158162
.from('user_subscriptions')
159163
.select('*')
@@ -189,6 +193,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
189193
// Sign in with Google
190194
const signInWithGoogle = async () => {
191195
try {
196+
// Store login method before OAuth redirect
197+
setLastLoginMethod('google')
198+
192199
const { data, error } = await supabase.auth.signInWithOAuth({
193200
provider: 'google',
194201
options: {
@@ -258,6 +265,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
258265

259266
// Create user record in the users table
260267
if (authData.user) {
268+
// Store login method for "last used" feature
269+
setLastLoginMethod('password')
270+
261271
const { error: userError } = await supabase
262272
.from('users')
263273
.insert({

src/lib/lastLoginMethod.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export type LoginMethod = 'password' | 'google'
2+
3+
const LAST_LOGIN_METHOD_KEY = 'lastLoginMethod'
4+
5+
export function setLastLoginMethod(method: LoginMethod): void {
6+
if (typeof window !== 'undefined') {
7+
localStorage.setItem(LAST_LOGIN_METHOD_KEY, method)
8+
}
9+
}
10+
11+
export function getLastLoginMethod(): LoginMethod | null {
12+
if (typeof window !== 'undefined') {
13+
const method = localStorage.getItem(LAST_LOGIN_METHOD_KEY)
14+
if (method === 'password' || method === 'google') {
15+
return method
16+
}
17+
}
18+
return null
19+
}
20+
21+
export function clearLastLoginMethod(): void {
22+
if (typeof window !== 'undefined') {
23+
localStorage.removeItem(LAST_LOGIN_METHOD_KEY)
24+
}
25+
}
26+
27+
export function getLoginMethodDisplayName(method: LoginMethod): string {
28+
switch (method) {
29+
case 'password':
30+
return 'Email & Password'
31+
case 'google':
32+
return 'Google'
33+
default:
34+
return 'Unknown'
35+
}
36+
}

0 commit comments

Comments
 (0)