shortening placeholder text
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 50s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 0s
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 50s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 0s
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useState, useCallback, useTransition, useRef, useEffect } from 'react';
|
import { useState, useCallback, useTransition, useRef, useEffect } from "react";
|
||||||
import { useRouter, useSearchParams, usePathname } from 'next/navigation';
|
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
||||||
import { isValidPostcode } from '@/lib/utils';
|
import { isValidPostcode } from "@/lib/utils";
|
||||||
import type { Filters, ResultFilters } from '@/lib/types';
|
import type { Filters, ResultFilters } from "@/lib/types";
|
||||||
import styles from './FilterBar.module.css';
|
import styles from "./FilterBar.module.css";
|
||||||
|
|
||||||
interface FilterBarProps {
|
interface FilterBarProps {
|
||||||
filters: Filters;
|
filters: Filters;
|
||||||
@@ -19,22 +19,28 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const currentSearch = searchParams.get('search') || '';
|
const currentSearch = searchParams.get("search") || "";
|
||||||
const currentPostcode = searchParams.get('postcode') || '';
|
const currentPostcode = searchParams.get("postcode") || "";
|
||||||
const currentRadius = searchParams.get('radius') || '1';
|
const currentRadius = searchParams.get("radius") || "1";
|
||||||
const initialOmniValue = currentPostcode || currentSearch;
|
const initialOmniValue = currentPostcode || currentSearch;
|
||||||
|
|
||||||
const [omniValue, setOmniValue] = useState(initialOmniValue);
|
const [omniValue, setOmniValue] = useState(initialOmniValue);
|
||||||
|
|
||||||
const currentLA = searchParams.get('local_authority') || '';
|
const currentLA = searchParams.get("local_authority") || "";
|
||||||
const currentType = searchParams.get('school_type') || '';
|
const currentType = searchParams.get("school_type") || "";
|
||||||
const currentPhase = searchParams.get('phase') || '';
|
const currentPhase = searchParams.get("phase") || "";
|
||||||
const currentGender = searchParams.get('gender') || '';
|
const currentGender = searchParams.get("gender") || "";
|
||||||
const currentAdmissionsPolicy = searchParams.get('admissions_policy') || '';
|
const currentAdmissionsPolicy = searchParams.get("admissions_policy") || "";
|
||||||
const currentHasSixthForm = searchParams.get('has_sixth_form') || '';
|
const currentHasSixthForm = searchParams.get("has_sixth_form") || "";
|
||||||
|
|
||||||
// Count active dropdown filters (not search/postcode, not phase since it's always visible)
|
// Count active dropdown filters (not search/postcode, not phase since it's always visible)
|
||||||
const activeDropdownFilters = [currentLA, currentType, currentGender, currentAdmissionsPolicy, currentHasSixthForm].filter(Boolean);
|
const activeDropdownFilters = [
|
||||||
|
currentLA,
|
||||||
|
currentType,
|
||||||
|
currentGender,
|
||||||
|
currentAdmissionsPolicy,
|
||||||
|
currentHasSixthForm,
|
||||||
|
].filter(Boolean);
|
||||||
const hasActiveDropdownFilters = activeDropdownFilters.length > 0;
|
const hasActiveDropdownFilters = activeDropdownFilters.length > 0;
|
||||||
const [filtersOpen, setFiltersOpen] = useState(hasActiveDropdownFilters);
|
const [filtersOpen, setFiltersOpen] = useState(hasActiveDropdownFilters);
|
||||||
|
|
||||||
@@ -45,47 +51,56 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if ((e.key === '/' || (e.key === 'k' && (e.ctrlKey || e.metaKey))) &&
|
if (
|
||||||
document.activeElement?.tagName !== 'INPUT' &&
|
(e.key === "/" || (e.key === "k" && (e.ctrlKey || e.metaKey))) &&
|
||||||
document.activeElement?.tagName !== 'TEXTAREA' &&
|
document.activeElement?.tagName !== "INPUT" &&
|
||||||
document.activeElement?.tagName !== 'SELECT') {
|
document.activeElement?.tagName !== "TEXTAREA" &&
|
||||||
|
document.activeElement?.tagName !== "SELECT"
|
||||||
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener('keydown', handleKeyDown);
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const updateURL = useCallback((updates: Record<string, string>) => {
|
const updateURL = useCallback(
|
||||||
const params = new URLSearchParams(searchParams);
|
(updates: Record<string, string>) => {
|
||||||
|
const params = new URLSearchParams(searchParams);
|
||||||
|
|
||||||
Object.entries(updates).forEach(([key, value]) => {
|
Object.entries(updates).forEach(([key, value]) => {
|
||||||
if (value && value !== '') {
|
if (value && value !== "") {
|
||||||
params.set(key, value);
|
params.set(key, value);
|
||||||
} else {
|
} else {
|
||||||
params.delete(key);
|
params.delete(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
params.delete('page');
|
params.delete("page");
|
||||||
|
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
router.push(`${pathname}?${params.toString()}`);
|
router.push(`${pathname}?${params.toString()}`);
|
||||||
});
|
});
|
||||||
}, [searchParams, pathname, router]);
|
},
|
||||||
|
[searchParams, pathname, router],
|
||||||
|
);
|
||||||
|
|
||||||
const handleSearchSubmit = (e: React.FormEvent) => {
|
const handleSearchSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!omniValue.trim()) {
|
if (!omniValue.trim()) {
|
||||||
updateURL({ search: '', postcode: '', radius: '' });
|
updateURL({ search: "", postcode: "", radius: "" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidPostcode(omniValue)) {
|
if (isValidPostcode(omniValue)) {
|
||||||
updateURL({ postcode: omniValue.trim().toUpperCase(), radius: currentRadius || '1', search: '' });
|
updateURL({
|
||||||
|
postcode: omniValue.trim().toUpperCase(),
|
||||||
|
radius: currentRadius || "1",
|
||||||
|
search: "",
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
updateURL({ search: omniValue.trim(), postcode: '', radius: '' });
|
updateURL({ search: omniValue.trim(), postcode: "", radius: "" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,25 +109,38 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleClearFilters = () => {
|
const handleClearFilters = () => {
|
||||||
setOmniValue('');
|
setOmniValue("");
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
router.push(pathname);
|
router.push(pathname);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasActiveFilters = currentSearch || currentLA || currentType || currentPhase || currentPostcode || currentGender || currentAdmissionsPolicy || currentHasSixthForm;
|
const hasActiveFilters =
|
||||||
|
currentSearch ||
|
||||||
|
currentLA ||
|
||||||
|
currentType ||
|
||||||
|
currentPhase ||
|
||||||
|
currentPostcode ||
|
||||||
|
currentGender ||
|
||||||
|
currentAdmissionsPolicy ||
|
||||||
|
currentHasSixthForm;
|
||||||
|
|
||||||
// Use result-scoped filter values when available, fall back to global
|
// Use result-scoped filter values when available, fall back to global
|
||||||
const laOptions = resultFilters?.local_authorities ?? filters.local_authorities;
|
const laOptions =
|
||||||
|
resultFilters?.local_authorities ?? filters.local_authorities;
|
||||||
const typeOptions = resultFilters?.school_types ?? filters.school_types;
|
const typeOptions = resultFilters?.school_types ?? filters.school_types;
|
||||||
const phaseOptions = resultFilters?.phases ?? filters.phases ?? [];
|
const phaseOptions = resultFilters?.phases ?? filters.phases ?? [];
|
||||||
const genderOptions = resultFilters?.genders ?? filters.genders ?? [];
|
const genderOptions = resultFilters?.genders ?? filters.genders ?? [];
|
||||||
const admissionsPolicyOptions = resultFilters?.admissions_policies ?? filters.admissions_policies ?? [];
|
const admissionsPolicyOptions =
|
||||||
|
resultFilters?.admissions_policies ?? filters.admissions_policies ?? [];
|
||||||
|
|
||||||
const isSecondaryMode = currentPhase === 'secondary' || genderOptions.length > 0;
|
const isSecondaryMode =
|
||||||
|
currentPhase === "secondary" || genderOptions.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.filterBar} ${isPending ? styles.isLoading : ''} ${isHero ? styles.heroMode : ''}`}>
|
<div
|
||||||
|
className={`${styles.filterBar} ${isPending ? styles.isLoading : ""} ${isHero ? styles.heroMode : ""}`}
|
||||||
|
>
|
||||||
<form onSubmit={handleSearchSubmit} className={styles.searchSection}>
|
<form onSubmit={handleSearchSubmit} className={styles.searchSection}>
|
||||||
<div className={styles.omniBoxContainer}>
|
<div className={styles.omniBoxContainer}>
|
||||||
<input
|
<input
|
||||||
@@ -120,11 +148,15 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
type="search"
|
type="search"
|
||||||
value={omniValue}
|
value={omniValue}
|
||||||
onChange={(e) => setOmniValue(e.target.value)}
|
onChange={(e) => setOmniValue(e.target.value)}
|
||||||
placeholder="Search by school name or postcode (e.g., SW1A 1AA)..."
|
placeholder="Search by school or postcode ..."
|
||||||
className={styles.omniInput}
|
className={styles.omniInput}
|
||||||
/>
|
/>
|
||||||
<button type="submit" className={`btn btn-primary ${styles.searchButton}`} disabled={isPending}>
|
<button
|
||||||
{isPending ? <div className={styles.spinner}></div> : 'Search'}
|
type="submit"
|
||||||
|
className={`btn btn-primary ${styles.searchButton}`}
|
||||||
|
disabled={isPending}
|
||||||
|
>
|
||||||
|
{isPending ? <div className={styles.spinner}></div> : "Search"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -137,7 +169,7 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
<label className={styles.radiusLabel}>Within:</label>
|
<label className={styles.radiusLabel}>Within:</label>
|
||||||
<select
|
<select
|
||||||
value={currentRadius}
|
value={currentRadius}
|
||||||
onChange={e => updateURL({ radius: e.target.value })}
|
onChange={(e) => updateURL({ radius: e.target.value })}
|
||||||
className={styles.controlSelect}
|
className={styles.controlSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
@@ -152,13 +184,15 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
{phaseOptions.length > 0 && (
|
{phaseOptions.length > 0 && (
|
||||||
<select
|
<select
|
||||||
value={currentPhase}
|
value={currentPhase}
|
||||||
onChange={(e) => handleFilterChange('phase', e.target.value)}
|
onChange={(e) => handleFilterChange("phase", e.target.value)}
|
||||||
className={styles.controlSelect}
|
className={styles.controlSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
<option value="">All Phases</option>
|
<option value="">All Phases</option>
|
||||||
{phaseOptions.map((p) => (
|
{phaseOptions.map((p) => (
|
||||||
<option key={p} value={p.toLowerCase()}>{p}</option>
|
<option key={p} value={p.toLowerCase()}>
|
||||||
|
{p}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)}
|
)}
|
||||||
@@ -166,14 +200,24 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.advancedToggle}
|
className={styles.advancedToggle}
|
||||||
onClick={() => setFiltersOpen(v => !v)}
|
onClick={() => setFiltersOpen((v) => !v)}
|
||||||
>
|
>
|
||||||
Advanced{hasActiveDropdownFilters ? ` (${activeDropdownFilters.length})` : ''}
|
Advanced
|
||||||
<span className={filtersOpen ? styles.chevronUp : styles.chevronDown} />
|
{hasActiveDropdownFilters
|
||||||
|
? ` (${activeDropdownFilters.length})`
|
||||||
|
: ""}
|
||||||
|
<span
|
||||||
|
className={filtersOpen ? styles.chevronUp : styles.chevronDown}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{hasActiveFilters && (
|
{hasActiveFilters && (
|
||||||
<button onClick={handleClearFilters} className={`btn btn-tertiary ${styles.clearButton}`} type="button" disabled={isPending}>
|
<button
|
||||||
|
onClick={handleClearFilters}
|
||||||
|
className={`btn btn-tertiary ${styles.clearButton}`}
|
||||||
|
type="button"
|
||||||
|
disabled={isPending}
|
||||||
|
>
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -183,25 +227,33 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
<div className={styles.filters}>
|
<div className={styles.filters}>
|
||||||
<select
|
<select
|
||||||
value={currentLA}
|
value={currentLA}
|
||||||
onChange={(e) => handleFilterChange('local_authority', e.target.value)}
|
onChange={(e) =>
|
||||||
|
handleFilterChange("local_authority", e.target.value)
|
||||||
|
}
|
||||||
className={styles.filterSelect}
|
className={styles.filterSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
<option value="">All Local Authorities</option>
|
<option value="">All Local Authorities</option>
|
||||||
{laOptions.map((la) => (
|
{laOptions.map((la) => (
|
||||||
<option key={la} value={la}>{la}</option>
|
<option key={la} value={la}>
|
||||||
|
{la}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={currentType}
|
value={currentType}
|
||||||
onChange={(e) => handleFilterChange('school_type', e.target.value)}
|
onChange={(e) =>
|
||||||
|
handleFilterChange("school_type", e.target.value)
|
||||||
|
}
|
||||||
className={styles.filterSelect}
|
className={styles.filterSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
<option value="">All School Types</option>
|
<option value="">All School Types</option>
|
||||||
{typeOptions.map((type) => (
|
{typeOptions.map((type) => (
|
||||||
<option key={type} value={type}>{type}</option>
|
<option key={type} value={type}>
|
||||||
|
{type}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -210,20 +262,26 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
{genderOptions.length > 0 && (
|
{genderOptions.length > 0 && (
|
||||||
<select
|
<select
|
||||||
value={currentGender}
|
value={currentGender}
|
||||||
onChange={(e) => handleFilterChange('gender', e.target.value)}
|
onChange={(e) =>
|
||||||
|
handleFilterChange("gender", e.target.value)
|
||||||
|
}
|
||||||
className={styles.filterSelect}
|
className={styles.filterSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
<option value="">Boys, Girls & Mixed</option>
|
<option value="">Boys, Girls & Mixed</option>
|
||||||
{genderOptions.map((g) => (
|
{genderOptions.map((g) => (
|
||||||
<option key={g} value={g.toLowerCase()}>{g}</option>
|
<option key={g} value={g.toLowerCase()}>
|
||||||
|
{g}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={currentHasSixthForm}
|
value={currentHasSixthForm}
|
||||||
onChange={(e) => handleFilterChange('has_sixth_form', e.target.value)}
|
onChange={(e) =>
|
||||||
|
handleFilterChange("has_sixth_form", e.target.value)
|
||||||
|
}
|
||||||
className={styles.filterSelect}
|
className={styles.filterSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
@@ -235,13 +293,17 @@ export function FilterBar({ filters, isHero, resultFilters }: FilterBarProps) {
|
|||||||
{admissionsPolicyOptions.length > 0 && (
|
{admissionsPolicyOptions.length > 0 && (
|
||||||
<select
|
<select
|
||||||
value={currentAdmissionsPolicy}
|
value={currentAdmissionsPolicy}
|
||||||
onChange={(e) => handleFilterChange('admissions_policy', e.target.value)}
|
onChange={(e) =>
|
||||||
|
handleFilterChange("admissions_policy", e.target.value)
|
||||||
|
}
|
||||||
className={styles.filterSelect}
|
className={styles.filterSelect}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
<option value="">All admissions types</option>
|
<option value="">All admissions types</option>
|
||||||
{admissionsPolicyOptions.map((p) => (
|
{admissionsPolicyOptions.map((p) => (
|
||||||
<option key={p} value={p.toLowerCase()}>{p}</option>
|
<option key={p} value={p.toLowerCase()}>
|
||||||
|
{p}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
* Modal for searching and adding schools to comparison
|
* Modal for searching and adding schools to comparison
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo } from "react";
|
||||||
import { Modal } from './Modal';
|
import { Modal } from "./Modal";
|
||||||
import { useComparison } from '@/hooks/useComparison';
|
import { useComparison } from "@/hooks/useComparison";
|
||||||
import { debounce } from '@/lib/utils';
|
import { debounce } from "@/lib/utils";
|
||||||
import { fetchSchools } from '@/lib/api';
|
import { fetchSchools } from "@/lib/api";
|
||||||
import type { School } from '@/lib/types';
|
import type { School } from "@/lib/types";
|
||||||
import styles from './SchoolSearchModal.module.css';
|
import styles from "./SchoolSearchModal.module.css";
|
||||||
|
|
||||||
interface SchoolSearchModalProps {
|
interface SchoolSearchModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -20,7 +20,7 @@ interface SchoolSearchModalProps {
|
|||||||
|
|
||||||
export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
||||||
const { addSchool, selectedSchools, canAddMore } = useComparison();
|
const { addSchool, selectedSchools, canAddMore } = useComparison();
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [results, setResults] = useState<School[]>([]);
|
const [results, setResults] = useState<School[]>([]);
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
const [hasSearched, setHasSearched] = useState(false);
|
const [hasSearched, setHasSearched] = useState(false);
|
||||||
@@ -37,17 +37,20 @@ export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
|||||||
|
|
||||||
setIsSearching(true);
|
setIsSearching(true);
|
||||||
try {
|
try {
|
||||||
const data = await fetchSchools({ search: term, page_size: 10 }, { cache: 'no-store' });
|
const data = await fetchSchools(
|
||||||
|
{ search: term, page_size: 10 },
|
||||||
|
{ cache: "no-store" },
|
||||||
|
);
|
||||||
setResults(data.schools || []);
|
setResults(data.schools || []);
|
||||||
setHasSearched(true);
|
setHasSearched(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Search failed:', error);
|
console.error("Search failed:", error);
|
||||||
setResults([]);
|
setResults([]);
|
||||||
} finally {
|
} finally {
|
||||||
setIsSearching(false);
|
setIsSearching(false);
|
||||||
}
|
}
|
||||||
}, 300),
|
}, 300),
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
const handleSearchChange = (value: string) => {
|
||||||
@@ -65,7 +68,7 @@ export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setSearchTerm('');
|
setSearchTerm("");
|
||||||
setResults([]);
|
setResults([]);
|
||||||
setHasSearched(false);
|
setHasSearched(false);
|
||||||
onClose();
|
onClose();
|
||||||
@@ -88,7 +91,7 @@ export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
|||||||
type="text"
|
type="text"
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => handleSearchChange(e.target.value)}
|
onChange={(e) => handleSearchChange(e.target.value)}
|
||||||
placeholder="Search by school name or location..."
|
placeholder="Search by school or postcode ..."
|
||||||
className={styles.searchInput}
|
className={styles.searchInput}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
@@ -114,17 +117,17 @@ export function SchoolSearchModal({ isOpen, onClose }: SchoolSearchModalProps) {
|
|||||||
{school.local_authority && (
|
{school.local_authority && (
|
||||||
<span>{school.local_authority}</span>
|
<span>{school.local_authority}</span>
|
||||||
)}
|
)}
|
||||||
{school.school_type && (
|
{school.school_type && <span>{school.school_type}</span>}
|
||||||
<span>{school.school_type}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleAddSchool(school)}
|
onClick={() => handleAddSchool(school)}
|
||||||
disabled={alreadySelected || !canAddMore}
|
disabled={alreadySelected || !canAddMore}
|
||||||
className={alreadySelected ? 'btn btn-active' : 'btn btn-secondary'}
|
className={
|
||||||
|
alreadySelected ? "btn btn-active" : "btn btn-secondary"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{alreadySelected ? '✓ Comparing' : '+ Compare'}
|
{alreadySelected ? "✓ Comparing" : "+ Compare"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user