Skip to content

Commit e6f2ecb

Browse files
committed
refactor: simplify SearchForm states, rewriting @hannes3r non-AGPL contribution
1 parent 8c7f25e commit e6f2ecb

3 files changed

Lines changed: 80 additions & 137 deletions

File tree

components/SearchForm/SearchForm.tsx

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,26 @@ import { useRouter } from "next/navigation";
44
import { useState } from "react";
55
import { extractUrlFromText } from "./extractUrlFromText";
66
import { URLInput } from "./URLInput";
7-
import { useSearchFormData } from "./useSearchFormData";
7+
import { useLocalStorage } from "./useLocalStorage";
88

99
export const SearchForm = () => {
1010
const router = useRouter();
1111
const [url, setUrl] = useState("");
1212
const [urlParseError, setUrlParseError] = useState<string | null>(null);
13-
const { formData, updateFormData } = useSearchFormData();
13+
14+
const [bahnCard, setBahnCard] = useLocalStorage("bahnCard", "none");
15+
16+
const [hasDeutschlandTicket, setHasDeutschlandTicket] = useLocalStorage(
17+
"hasDeutschlandTicket",
18+
false
19+
);
20+
21+
const [passengerAge, setPassengerAge] = useLocalStorage<string>(
22+
"passengerAge",
23+
""
24+
);
25+
26+
const [travelClass, setTravelClass] = useLocalStorage("travelClass", "2");
1427

1528
const handleUrlParsingAndNavigation = () => {
1629
if (!url.trim()) {
@@ -31,10 +44,10 @@ export const SearchForm = () => {
3144

3245
const searchParams = new URLSearchParams({
3346
url: extractedUrl,
34-
bahnCard: formData.bahnCard,
35-
hasDeutschlandTicket: String(formData.hasDeutschlandTicket),
36-
passengerAge: String(formData.passengerAge),
37-
travelClass: formData.travelClass,
47+
bahnCard,
48+
hasDeutschlandTicket: String(hasDeutschlandTicket),
49+
passengerAge: String(passengerAge),
50+
travelClass,
3851
// autoSearch: "true", // Flag to indicate auto-search should happen
3952
});
4053

@@ -48,46 +61,52 @@ export const SearchForm = () => {
4861
<URLInput url={url} setUrl={setUrl} />
4962
<div className="flex flex-col md:flex-row gap-8">
5063
<select
51-
value={formData.bahnCard}
52-
onChange={(e) => updateFormData({ bahnCard: e.target.value })}
64+
value={bahnCard}
65+
onChange={(e) => setBahnCard(e.target.value)}
5366
className="w-full px-3 py-2 resize-vertical border-b-2 border-gray-300 focus:ring-2 focus:ring-primary"
5467
>
55-
<option className="text-black" value="none">Keine BahnCard</option>
56-
<option className="text-black" value="25">BahnCard 25 </option>
57-
<option className="text-black" value="50">BahnCard 50 </option>
68+
<option className="text-black" value="none">
69+
Keine BahnCard
70+
</option>
71+
<option className="text-black" value="25">
72+
BahnCard 25{" "}
73+
</option>
74+
<option className="text-black" value="50">
75+
BahnCard 50{" "}
76+
</option>
5877
</select>
5978
<input
6079
type="number"
61-
value={formData.passengerAge}
62-
onChange={(e) => updateFormData({ passengerAge: e.target.value })}
80+
value={passengerAge}
81+
onChange={(e) => setPassengerAge(e.target.value)}
6382
placeholder="Alter des Reisenden"
6483
min="0"
6584
max="120"
6685
className="w-full px-3 py-2 resize-vertical border-b-2 border-gray-300 focus:ring-2 focus:ring-primary"
6786
/>
6887
<select
69-
value={String(formData.hasDeutschlandTicket)}
70-
onChange={(e) =>
71-
updateFormData({
72-
hasDeutschlandTicket: e.target.value === "true",
73-
})
74-
}
88+
value={String(hasDeutschlandTicket)}
89+
onChange={(e) => setHasDeutschlandTicket(e.target.value === "true")}
7590
className="w-full px-3 py-2 resize-vertical border-b-2 border-gray-300 focus:ring-2 focus:ring-primary"
7691
>
77-
<option className="text-black" value="true">Deutschlandticket</option>
78-
<option className="text-black" value="false">Kein Deutschlandticket</option>
92+
<option className="text-black" value="true">
93+
Deutschlandticket
94+
</option>
95+
<option className="text-black" value="false">
96+
Kein Deutschlandticket
97+
</option>
7998
</select>
8099
<select
81-
value={String(formData.travelClass)}
82-
onChange={(e) =>
83-
updateFormData({
84-
travelClass: e.target.value,
85-
})
86-
}
100+
value={String(travelClass)}
101+
onChange={(e) => setTravelClass(e.target.value)}
87102
className="w-full px-3 py-2 resize-vertical border-b-2 border-gray-300 focus:ring-2 focus:ring-primary"
88103
>
89-
<option className="text-black" value="1">Erste Klasse</option>
90-
<option className="text-black" value="2">Zweite Klasse</option>
104+
<option className="text-black" value="1">
105+
Erste Klasse
106+
</option>
107+
<option className="text-black" value="2">
108+
Zweite Klasse
109+
</option>
91110
</select>
92111
</div>
93112

@@ -105,6 +124,6 @@ export const SearchForm = () => {
105124
<strong>Fehler:</strong> {urlParseError}
106125
</div>
107126
)}
108-
</section >
127+
</section>
109128
);
110129
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useEffect, useState } from "react";
2+
3+
export const useLocalStorage = <T>(key: string, initialValue: T) => {
4+
const [value, setValueInternal] = useState(() => initialValue);
5+
6+
const initialize = () => {
7+
if (typeof window === "undefined") {
8+
return initialValue;
9+
}
10+
11+
const stringified = window.localStorage.getItem(key);
12+
13+
if (stringified === null) {
14+
return initialValue;
15+
}
16+
17+
return JSON.parse(stringified) as T;
18+
};
19+
20+
// prevents hydration error so that state is only initialized after server is defined
21+
useEffect(() => {
22+
setValueInternal(initialize());
23+
}, []);
24+
25+
const setValueExternal = (newValue: T) => {
26+
setValueInternal(newValue);
27+
window.localStorage.setItem(key, JSON.stringify(newValue));
28+
};
29+
30+
return [value, setValueExternal] as const;
31+
};

components/SearchForm/useSearchFormData.ts

Lines changed: 0 additions & 107 deletions
This file was deleted.

0 commit comments

Comments
 (0)