Initial commit
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { apiGet } from "./api/client";
|
||||
|
||||
export default function App() {
|
||||
const [salons, setSalons] = useState([]);
|
||||
const [query, setQuery] = useState("");
|
||||
const [status, setStatus] = useState("idle");
|
||||
|
||||
useEffect(() => {
|
||||
let ignore = false;
|
||||
|
||||
async function load() {
|
||||
setStatus("loading");
|
||||
try {
|
||||
const data = await apiGet(`/salons/?q=${encodeURIComponent(query)}`);
|
||||
if (!ignore) {
|
||||
setSalons(data);
|
||||
setStatus("ready");
|
||||
}
|
||||
} catch (error) {
|
||||
if (!ignore) {
|
||||
setStatus("error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load();
|
||||
return () => {
|
||||
ignore = true;
|
||||
};
|
||||
}, [query]);
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<header className="hero">
|
||||
<p className="eyebrow">Salon Booking Platform</p>
|
||||
<h1>Find, compare, and book top salons near you.</h1>
|
||||
<p className="subtitle">
|
||||
Search by city or service, compare pricing, and lock in your slot in seconds.
|
||||
</p>
|
||||
<div className="search">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search by salon or service"
|
||||
value={query}
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section className="results">
|
||||
<h2>Salons</h2>
|
||||
{status === "loading" && <p>Loading salons...</p>}
|
||||
{status === "error" && (
|
||||
<p className="error">Unable to load salons. Start the backend API to see results.</p>
|
||||
)}
|
||||
{status === "ready" && salons.length === 0 && <p>No salons found.</p>}
|
||||
<div className="grid">
|
||||
{salons.map((salon) => (
|
||||
<article className="card" key={salon.id}>
|
||||
<div className="card-header">
|
||||
<h3>{salon.name}</h3>
|
||||
<span className="rating">{salon.rating_avg} / 5</span>
|
||||
</div>
|
||||
<p>{salon.description || "No description yet."}</p>
|
||||
<div className="meta">
|
||||
<span>{salon.city}</span>
|
||||
<span>{salon.phone_number || "Phone unavailable"}</span>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user