Skip to content

Commit 2e505fd

Browse files
committed
Split matching components into smaller compnents
1 parent ab5b9b4 commit 2e505fd

File tree

5 files changed

+227
-141
lines changed

5 files changed

+227
-141
lines changed

frontend/app/app/matching/page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import AuthPageWrapper from "@/components/auth/auth-page-wrapper";
2+
import FindMatch from "@/components/matching/find-match";
3+
import { Suspense } from "react";
4+
5+
export default function QuestionListingPage() {
6+
return (
7+
<AuthPageWrapper requireLoggedIn>
8+
<Suspense>
9+
<FindMatch />
10+
</Suspense>
11+
</AuthPageWrapper>
12+
);
13+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"use client";
2+
import React, { useState, useEffect } from "react";
3+
import { MatchForm } from "@/components/matching/matching-form";
4+
import { SearchProgress } from "@/components/matching/search-progress";
5+
import { SelectionSummary } from "@/components/matching/selection-summary";
6+
import { useToast } from "@/components/hooks/use-toast";
7+
8+
export default function FindMatch() {
9+
const [selectedDifficulty, setSelectedDifficulty] = useState<string>("");
10+
const [selectedTopic, setSelectedTopic] = useState<string>("");
11+
const [isSearching, setIsSearching] = useState<boolean>(false);
12+
const [waitTime, setWaitTime] = useState<number>(0);
13+
const { toast } = useToast();
14+
15+
useEffect(() => {
16+
let interval: NodeJS.Timeout | undefined;
17+
if (isSearching) {
18+
interval = setInterval(() => {
19+
setWaitTime((prevTime) => prevTime + 1);
20+
}, 1000);
21+
} else {
22+
setWaitTime(0);
23+
}
24+
return () => clearInterval(interval);
25+
}, [isSearching]);
26+
27+
const handleSearch = () => {
28+
if (selectedDifficulty && selectedTopic) {
29+
setIsSearching(true);
30+
} else {
31+
toast({
32+
title: "Invalid Selection",
33+
description: "Please select both a difficulty level and a topic",
34+
variant: "destructive",
35+
});
36+
}
37+
};
38+
39+
const handleCancel = () => {
40+
setIsSearching(false);
41+
setWaitTime(0);
42+
};
43+
44+
return (
45+
<div className="container mx-auto p-4">
46+
<MatchForm
47+
selectedDifficulty={selectedDifficulty}
48+
setSelectedDifficulty={setSelectedDifficulty}
49+
selectedTopic={selectedTopic}
50+
setSelectedTopic={setSelectedTopic}
51+
handleSearch={handleSearch}
52+
isSearching={isSearching}
53+
handleCancel={handleCancel}
54+
/>
55+
56+
{isSearching && <SearchProgress waitTime={waitTime} />}
57+
58+
{!isSearching && (selectedDifficulty || selectedTopic) && (
59+
<SelectionSummary
60+
selectedDifficulty={selectedDifficulty}
61+
selectedTopic={selectedTopic}
62+
/>
63+
)}
64+
</div>
65+
);
66+
}
Lines changed: 82 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"use client";
2-
3-
import React, { useState, useEffect } from "react";
1+
import React from "react";
42
import { Button } from "@/components/ui/button";
53
import {
64
Card,
@@ -18,9 +16,6 @@ import {
1816
SelectValue,
1917
} from "@/components/ui/select";
2018
import { Label } from "@/components/ui/label";
21-
import { Progress } from "@/components/ui/progress";
22-
import { AlertCircle, Clock } from "lucide-react";
23-
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
2419

2520
const difficulties: string[] = ["Easy", "Medium", "Hard"];
2621
const topics: string[] = [
@@ -32,143 +27,89 @@ const topics: string[] = [
3227
"Dynamic Programming",
3328
];
3429

35-
export default function MatchingForm() {
36-
const [selectedDifficulty, setSelectedDifficulty] = useState<string>("");
37-
const [selectedTopic, setSelectedTopic] = useState<string>("");
38-
const [isSearching, setIsSearching] = useState<boolean>(false);
39-
const [waitTime, setWaitTime] = useState<number>(0);
40-
41-
useEffect(() => {
42-
let interval: NodeJS.Timeout | undefined;
43-
if (isSearching) {
44-
interval = setInterval(() => {
45-
setWaitTime((prevTime) => prevTime + 1);
46-
}, 1000);
47-
} else {
48-
setWaitTime(0);
49-
}
50-
return () => clearInterval(interval);
51-
}, [isSearching]);
52-
53-
const handleSearch = () => {
54-
if (selectedDifficulty && selectedTopic) {
55-
setIsSearching(true);
56-
} else {
57-
alert("Please select both a difficulty level and a topic");
58-
}
59-
};
60-
61-
const handleCancel = () => {
62-
setIsSearching(false);
63-
setWaitTime(0);
64-
};
30+
interface MatchFormProps {
31+
selectedDifficulty: string;
32+
setSelectedDifficulty: (difficulty: string) => void;
33+
selectedTopic: string;
34+
setSelectedTopic: (topic: string) => void;
35+
handleSearch: () => void;
36+
isSearching: boolean;
37+
handleCancel: () => void;
38+
}
6539

40+
export function MatchForm({
41+
selectedDifficulty,
42+
setSelectedDifficulty,
43+
selectedTopic,
44+
setSelectedTopic,
45+
handleSearch,
46+
isSearching,
47+
handleCancel,
48+
}: MatchFormProps) {
6649
return (
67-
<div className="container mx-auto p-4">
68-
<Card className="w-full max-w-2xl mx-auto">
69-
<CardHeader>
70-
<CardTitle>Find a Match</CardTitle>
71-
<CardDescription>
72-
Select your preferred difficulty level and topic to find a match.
73-
</CardDescription>
74-
</CardHeader>
75-
<CardContent>
76-
<div className="space-y-6">
77-
<div>
78-
<Label
79-
htmlFor="difficulty-select"
80-
className="text-lg font-medium mb-2 block"
81-
>
82-
Difficulty Level
83-
</Label>
84-
<Select
85-
value={selectedDifficulty}
86-
onValueChange={setSelectedDifficulty}
87-
>
88-
<SelectTrigger id="difficulty-select">
89-
<SelectValue placeholder="Select difficulty" />
90-
</SelectTrigger>
91-
<SelectContent>
92-
{difficulties.map((difficulty) => (
93-
<SelectItem key={difficulty} value={difficulty}>
94-
{difficulty}
95-
</SelectItem>
96-
))}
97-
</SelectContent>
98-
</Select>
99-
</div>
100-
<div>
101-
<Label
102-
htmlFor="topic-select"
103-
className="text-lg font-medium mb-2 block"
104-
>
105-
Topic
106-
</Label>
107-
<Select value={selectedTopic} onValueChange={setSelectedTopic}>
108-
<SelectTrigger id="topic-select">
109-
<SelectValue placeholder="Select topic" />
110-
</SelectTrigger>
111-
<SelectContent>
112-
{topics.map((topic) => (
113-
<SelectItem key={topic} value={topic}>
114-
{topic}
115-
</SelectItem>
116-
))}
117-
</SelectContent>
118-
</Select>
119-
</div>
50+
<Card className="w-full max-w-2xl mx-auto">
51+
<CardHeader>
52+
<CardTitle>Find a Match</CardTitle>
53+
<CardDescription>
54+
Select your preferred difficulty level and topic to find a match.
55+
</CardDescription>
56+
</CardHeader>
57+
<CardContent>
58+
<div className="space-y-6">
59+
<div>
60+
<Label
61+
htmlFor="difficulty-select"
62+
className="text-lg font-medium mb-2 block"
63+
>
64+
Difficulty Level
65+
</Label>
66+
<Select
67+
value={selectedDifficulty}
68+
onValueChange={setSelectedDifficulty}
69+
>
70+
<SelectTrigger id="difficulty-select">
71+
<SelectValue placeholder="Select difficulty" />
72+
</SelectTrigger>
73+
<SelectContent>
74+
{difficulties.map((difficulty) => (
75+
<SelectItem key={difficulty} value={difficulty}>
76+
{difficulty}
77+
</SelectItem>
78+
))}
79+
</SelectContent>
80+
</Select>
12081
</div>
121-
</CardContent>
122-
<CardFooter className="flex justify-between">
123-
{!isSearching ? (
124-
<Button onClick={handleSearch}>Find Match</Button>
125-
) : (
126-
<Button variant="destructive" onClick={handleCancel}>
127-
Cancel Search
128-
</Button>
129-
)}
130-
</CardFooter>
131-
</Card>
132-
133-
{isSearching && (
134-
<Card className="w-full max-w-2xl mx-auto mt-4">
135-
<CardHeader>
136-
<CardTitle>Searching for Match</CardTitle>
137-
<CardDescription>
138-
Please wait while we find a suitable match for you.
139-
</CardDescription>
140-
</CardHeader>
141-
<CardContent>
142-
<div className="space-y-4">
143-
<Progress
144-
value={(waitTime % 60) * (100 / 60)}
145-
className="w-full"
146-
/>
147-
<div className="flex items-center justify-between">
148-
<div className="flex items-center space-x-2">
149-
<Clock className="h-4 w-4" />
150-
<span>
151-
Wait Time: {Math.floor(waitTime / 60)}:
152-
{(waitTime % 60).toString().padStart(2, "0")}
153-
</span>
154-
</div>
155-
<span>Searching...</span>
156-
</div>
157-
</div>
158-
</CardContent>
159-
</Card>
160-
)}
161-
162-
{!isSearching && (selectedDifficulty || selectedTopic) && (
163-
<Alert className="w-full max-w-2xl mx-auto mt-4">
164-
<AlertCircle className="h-4 w-4" />
165-
<AlertTitle>Selection Summary</AlertTitle>
166-
<AlertDescription>
167-
<p>Difficulty: {selectedDifficulty || "None selected"}</p>
168-
<p>Topic: {selectedTopic || "None selected"}</p>
169-
</AlertDescription>
170-
</Alert>
171-
)}
172-
</div>
82+
<div>
83+
<Label
84+
htmlFor="topic-select"
85+
className="text-lg font-medium mb-2 block"
86+
>
87+
Topic
88+
</Label>
89+
<Select value={selectedTopic} onValueChange={setSelectedTopic}>
90+
<SelectTrigger id="topic-select">
91+
<SelectValue placeholder="Select topic" />
92+
</SelectTrigger>
93+
<SelectContent>
94+
{topics.map((topic) => (
95+
<SelectItem key={topic} value={topic}>
96+
{topic}
97+
</SelectItem>
98+
))}
99+
</SelectContent>
100+
</Select>
101+
</div>
102+
</div>
103+
</CardContent>
104+
<CardFooter className="flex justify-between">
105+
{!isSearching ? (
106+
<Button onClick={handleSearch}>Find Match</Button>
107+
) : (
108+
<Button variant="destructive" onClick={handleCancel}>
109+
Cancel Search
110+
</Button>
111+
)}
112+
</CardFooter>
113+
</Card>
173114
);
174115
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from "react";
2+
import {
3+
Card,
4+
CardContent,
5+
CardDescription,
6+
CardHeader,
7+
CardTitle,
8+
} from "@/components/ui/card";
9+
import { Progress } from "@/components/ui/progress";
10+
import { Clock } from "lucide-react";
11+
12+
interface SearchProgressProps {
13+
waitTime: number;
14+
}
15+
16+
export function SearchProgress({ waitTime }: SearchProgressProps) {
17+
return (
18+
<Card className="w-full max-w-2xl mx-auto mt-4">
19+
<CardHeader>
20+
<CardTitle>Searching for Match</CardTitle>
21+
<CardDescription>
22+
Please wait while we find a suitable match for you.
23+
</CardDescription>
24+
</CardHeader>
25+
<CardContent>
26+
<div className="space-y-4">
27+
<Progress value={(waitTime % 60) * (100 / 60)} className="w-full" />
28+
<div className="flex items-center justify-between">
29+
<div className="flex items-center space-x-2">
30+
<Clock className="h-4 w-4" />
31+
<span>
32+
Wait Time: {Math.floor(waitTime / 60)}:
33+
{(waitTime % 60).toString().padStart(2, "0")}
34+
</span>
35+
</div>
36+
<span>Searching...</span>
37+
</div>
38+
</div>
39+
</CardContent>
40+
</Card>
41+
);
42+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react";
2+
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
3+
import { AlertCircle } from "lucide-react";
4+
5+
interface SelectionSummaryProps {
6+
selectedDifficulty: string;
7+
selectedTopic: string;
8+
}
9+
10+
export function SelectionSummary({
11+
selectedDifficulty,
12+
selectedTopic,
13+
}: SelectionSummaryProps) {
14+
return (
15+
<Alert className="w-full max-w-2xl mx-auto mt-4">
16+
<AlertCircle className="h-4 w-4" />
17+
<AlertTitle>Selection Summary</AlertTitle>
18+
<AlertDescription>
19+
<p>Difficulty: {selectedDifficulty || "None selected"}</p>
20+
<p>Topic: {selectedTopic || "None selected"}</p>
21+
</AlertDescription>
22+
</Alert>
23+
);
24+
}

0 commit comments

Comments
 (0)