1 import { useState } from "react";
2 import { useQuery } from "@tanstack/react-query";
3 import DeviceSelector from "@/components/repair/device-selector";
4 import CategoryGrid from "@/components/repair/category-grid";
5 import GuideCard from "@/components/repair/guide-card";
6 import PartsIdentification from "@/components/repair/parts-identification";
7 import TroubleshootingFlowchart from "@/components/repair/troubleshooting-flowchart";
8 import SoftwareLinks from "@/components/repair/software-links";
9 import FloatingActionButton from "@/components/repair/floating-action-button";
10 import GuideDetailModal from "@/components/repair/guide-detail-modal";
11 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
12 import { Sparkles, Filter, LayoutGrid } from "lucide-react";
13 import type { RepairGuide } from "@shared/schema";
14
15 export default function Home() {
16 const [selectedDeviceType, setSelectedDeviceType] = useState<"laptop" | "desktop">("laptop");
17 const [selectedCategory, setSelectedCategory] = useState<string>("");
18 const [sortOption, setSortOption] = useState<string>("popular");
19 const [selectedGuideId, setSelectedGuideId] = useState<string | null>(null);
20
21 const { data: repairGuides = [], isLoading } = useQuery<RepairGuide[]>({
22 queryKey: ["api", "repair-guides"], // Configured queryClient handles prefixing and base URL
23 });
24
25 const sortedGuides = [...repairGuides].sort((a, b) => {
26 switch (sortOption) {
27 case "difficulty":
28 const difficultyOrder = { easy: 1, medium: 2, hard: 3 };
29 return difficultyOrder[a.difficulty as keyof typeof difficultyOrder] - difficultyOrder[b.difficulty as keyof typeof difficultyOrder];
30 case "time":
31 return a.estimatedTime.localeCompare(b.estimatedTime);
32 case "popular":
33 default:
34 return (b.viewCount || 0) - (a.viewCount || 0);
35 }
36 });
37
38 const filteredGuides = sortedGuides.filter(guide => {
39 const matchesDevice = !selectedDeviceType || guide.deviceType === selectedDeviceType;
40 const matchesCategory = !selectedCategory || guide.category === selectedCategory;
41 return matchesDevice && matchesCategory;
42 });
43
44 return (
45 <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10 space-y-16">
46
47 {/* Top Hero Section (Internal) */}
48 <section className="relative overflow-hidden rounded-[2.5rem] bg-primary/5 border border-primary/10 p-8 md:p-12">
49 <div className="relative z-10 max-w-2xl">
50 <div className="flex items-center gap-2 text-primary font-bold text-xs uppercase tracking-widest mb-4">
51 <Sparkles className="h-4 w-4" /> Welcome back, Technician
52 </div>
53 <h1 className="text-4xl md:text-5xl font-extrabold tracking-tight mb-6">
54 What are we fixing today?
55 </h1>
56 <DeviceSelector
57 selectedType={selectedDeviceType}
58 onTypeChange={setSelectedDeviceType}
59 />
60 </div>
61 <div className="absolute right-[-10%] top-[-10%] w-[50%] h-[120%] bg-gradient-to-l from-primary/10 to-transparent -z-0 blur-3xl opacity-50" />
62 </section>
63
64 {/* Categories Section */}
65 <section className="space-y-6">
66 <div className="flex items-center gap-3">
67 <div className="h-8 w-1 bg-primary rounded-full" />
68 <h2 className="text-2xl font-bold">Categories</h2>
69 </div>
70 <CategoryGrid
71 selectedCategory={selectedCategory}
72 onCategoryChange={setSelectedCategory}
73 deviceType={selectedDeviceType}
74 />
75 </section>
76
77 {/* Guides Grid Section */}
78 <section className="space-y-8">
79 <div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
80 <div className="flex items-center gap-3">
81 <div className="h-8 w-1 bg-primary rounded-full" />
82 <h2 className="text-2xl font-bold">Explore Guides</h2>
83 </div>
84
85 <div className="flex items-center gap-2">
86 <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-muted/50 border border-border/50 text-xs font-semibold">
87 <Filter className="h-3 w-3" /> Sort by:
88 </div>
89 <Select value={sortOption} onValueChange={setSortOption}>
90 <SelectTrigger className="w-44 h-10 rounded-full border-border/50 bg-background shadow-sm ring-primary/5">
91 <SelectValue />
92 </SelectTrigger>
93 <SelectContent className="rounded-2xl shadow-glass border-border/50">
94 <SelectItem value="popular">Popularity</SelectItem>
95 <SelectItem value="difficulty">Difficulty Level</SelectItem>
96 <SelectItem value="time">Time Estimate</SelectItem>
97 </SelectContent>
98 </Select>
99 </div>
100 </div>
101
102 {isLoading ? (
103 <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8">
104 {[...Array(6)].map((_, i) => (
105 <div key={i} className="h-80 rounded-3xl bg-muted/30 animate-pulse" />
106 ))}
107 </div>
108 ) : (
109 <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8">
110 {filteredGuides.map(guide => (
111 <div key={guide.id} className="transition-all hover:translate-y-[-4px]">
112 <GuideCard
113 guide={guide}
114 onViewGuide={() => setSelectedGuideId(guide.id)}
115 />
116 </div>
117 ))}
118 </div>
119 )}
120
121 {!isLoading && filteredGuides.length === 0 && (
122 <div className="text-center py-20 bg-muted/10 rounded-[3rem] border border-dashed border-border/60">
123 <div className="inline-flex h-20 w-20 items-center justify-center rounded-full bg-muted mb-6">
124 <LayoutGrid className="h-10 w-10 text-muted-foreground/40" />
125 </div>
126 <h3 className="text-xl font-bold mb-2">No guides found</h3>
127 <p className="text-muted-foreground">Try broadening your search or selecting a different device type.</p>
128 </div>
129 )}
130 </section>
131
132 {/* Feature Sections with Refined Spacing */}
133 <section className="grid grid-cols-1 gap-16 pt-8 pb-10">
134 <div className="space-y-6">
135 <div className="flex items-center gap-3">
136 <div className="h-8 w-1 bg-indigo-500 rounded-full" />
137 <h2 className="text-2xl font-bold">Quick Diagnostics</h2>
138 </div>
139 <TroubleshootingFlowchart />
140 </div>
141
142 <div className="space-y-6">
143 <div className="flex items-center gap-3">
144 <div className="h-8 w-1 bg-emerald-500 rounded-full" />
145 <h2 className="text-2xl font-bold">Hardware Explorer</h2>
146 </div>
147 <PartsIdentification deviceType={selectedDeviceType} />
148 </div>
149
150 <div className="space-y-6">
151 <div className="flex items-center gap-3">
152 <div className="h-8 w-1 bg-amber-500 rounded-full" />
153 <h2 className="text-2xl font-bold">Technical Toolbelt</h2>
154 </div>
155 <SoftwareLinks deviceType={selectedDeviceType} />
156 </div>
157 </section>
158
159 <FloatingActionButton />
160
161 {selectedGuideId && (
162 <GuideDetailModal
163 guideId={selectedGuideId}
164 onClose={() => setSelectedGuideId(null)}
165 />
166 )}
167 </div>
168 );
169 }