Refactoring: port small part of OHInput into svelte

This commit is contained in:
Pieter Vander Vennet 2024-07-29 20:35:45 +02:00
parent 013c2e4b61
commit 5f355aa3e2
3 changed files with 101 additions and 116 deletions

View file

@ -10,9 +10,10 @@ import Combine from "../Base/Combine"
import { FixedUiElement } from "../Base/FixedUiElement"
import { OH, OpeningHour } from "./OpeningHours"
import { InputElement } from "../Input/InputElement"
import PublicHolidayInput from "./PublicHolidayInput"
import Translations from "../i18n/Translations"
import BaseUIElement from "../BaseUIElement"
import SvelteUIElement from "../Base/SvelteUIElement"
import PublicHolidaySelector from "./PublicHolidaySelector.svelte"
export default class OpeningHoursInput extends InputElement<string> {
private readonly _value: UIEventSource<string>
@ -87,19 +88,19 @@ export default class OpeningHoursInput extends InputElement<string> {
break
}
}
const phSelector = new PublicHolidayInput(new UIEventSource<string>(ph))
const phSelectorValue = new UIEventSource<string>(ph ?? "")
// Note: MUST be bound AFTER the leftover rules!
const rulesFromOhPicker: UIEventSource<OpeningHour[]> = valueWithoutPrefix.sync(
(str) => {
return OH.Parse(str)
},
[leftoverRules, phSelector.GetValue()],
[leftoverRules, phSelectorValue],
(rules, oldString) => {
// We always add a ';', to easily add new rules. We remove the ';' again at the end of the function
// Important: spaces are _not_ allowed after a ';' as it'll destabilize the parsing!
let str = OH.ToString(rules) + ";"
const ph = phSelector.GetValue().data
const ph = phSelectorValue.data
if (ph) {
str += ph + ";"
}
@ -138,7 +139,7 @@ export default class OpeningHoursInput extends InputElement<string> {
const ohPicker = new OpeningHoursPicker(rulesFromOhPicker)
this._element = new Combine([leftoverWarning, ohPicker, phSelector])
this._element = new Combine([leftoverWarning, ohPicker, new SvelteUIElement(PublicHolidaySelector, {value: phSelectorValue})])
}
GetValue(): UIEventSource<string> {

View file

@ -1,111 +0,0 @@
import { OH } from "./OpeningHours"
import { UIEventSource } from "../../Logic/UIEventSource"
import Combine from "../Base/Combine"
import { TextField } from "../Input/TextField"
import { DropDown } from "../Input/DropDown"
import { InputElement } from "../Input/InputElement"
import Translations from "../i18n/Translations"
import Toggle from "../Input/Toggle"
export default class PublicHolidayInput extends InputElement<string> {
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false)
private readonly _value: UIEventSource<string>
constructor(value: UIEventSource<string> = new UIEventSource<string>("")) {
super()
this._value = value
}
GetValue(): UIEventSource<string> {
return this._value
}
IsValid(_: string): boolean {
return true
}
protected InnerConstructElement(): HTMLElement {
const dropdown = new DropDown(Translations.t.general.opening_hours.open_during_ph.Clone(), [
{ shown: Translations.t.general.opening_hours.ph_not_known.Clone(), value: "" },
{ shown: Translations.t.general.opening_hours.ph_closed.Clone(), value: "off" },
{ shown: Translations.t.general.opening_hours.ph_open_as_usual.Clone(), value: "open" },
{ shown: Translations.t.general.opening_hours.ph_open.Clone(), value: " " },
]).SetClass("inline-block w-full")
/*
* Either "" (unknown), " " (opened) or "off" (closed)
* */
const mode = dropdown.GetValue()
const start = new TextField({
placeholder: "starthour",
htmlType: "time",
}).SetClass("inline-block")
const end = new TextField({
placeholder: "starthour",
htmlType: "time",
}).SetClass("inline-block")
const askHours = new Toggle(
new Combine([
Translations.t.general.opening_hours.opensAt.Clone(),
start,
Translations.t.general.opening_hours.openTill.Clone(),
end,
]),
undefined,
mode.map((mode) => mode === " ")
)
this.SetupDataSync(mode, start.GetValue(), end.GetValue())
return new Combine([dropdown, askHours]).SetClass("w-full flex").ConstructElement()
}
private SetupDataSync(
mode: UIEventSource<string>,
startTime: UIEventSource<string>,
endTime: UIEventSource<string>
) {
const value = this._value
value
.map((ph) => OH.ParsePHRule(ph))
.addCallbackAndRunD((parsed) => {
if (parsed === null) {
return
}
mode.setData(parsed.mode)
startTime.setData(parsed.start)
endTime.setData(parsed.end)
})
// We use this as a 'addCallbackAndRun'
mode.map(
(mode) => {
if (mode === undefined || mode === "") {
// not known
value.setData(undefined)
return
}
if (mode === "off") {
value.setData("PH off")
return
}
if (mode === "open") {
value.setData("PH open")
return
}
// Open during PH with special hours
if (startTime.data === undefined || endTime.data === undefined) {
// hours not filled in - not saveable
value.setData(undefined)
return
}
const oh = `PH ${startTime.data}-${endTime.data}`
value.setData(oh)
},
[startTime, endTime]
)
}
}

View file

@ -0,0 +1,95 @@
<script lang="ts">
import { UIEventSource } from "../../Logic/UIEventSource"
import Dropdown from "../Base/Dropdown.svelte"
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
import ToSvelte from "../Base/ToSvelte.svelte"
import { TextField } from "../Input/TextField"
import { OH } from "./OpeningHours"
export let value: UIEventSource<string>
let startValue: UIEventSource<string> = new UIEventSource<string>(undefined)
let endValue: UIEventSource<string> = new UIEventSource<string>(undefined)
const t = Translations.t.general.opening_hours
let mode = new UIEventSource("")
value
.map((ph) => OH.ParsePHRule(ph))
.addCallbackAndRunD((parsed) => {
if (parsed === null) {
return
}
mode.setData(parsed.mode)
startValue.setData(parsed.start)
endValue.setData(parsed.end)
})
function updateValue() {
if (mode.data === undefined || mode.data === "") {
// not known
value.setData("")
} else if (mode.data === "off") {
value.setData("PH off")
} else if (mode.data === "open") {
value.setData("PH open")
} else if (startValue.data === undefined || endValue.data === undefined) {
// Open during PH with special hours
// hours not filled in - not saveable
value.setData(undefined)
} else {
value.setData(`PH ${startValue.data}-${endValue.data}`)
}
}
startValue.addCallbackAndRunD(() => updateValue())
endValue.addCallbackAndRunD(() => updateValue())
mode.addCallbackAndRunD(() => updateValue())
</script>
<label>
<Tr t={t.open_during_ph} />
<Dropdown value={mode}>
<option value={""}>
<Tr t={t.ph_not_known} />
</option>
<option value={"off"}>
<Tr t={t.ph_closed} />
</option>
<option value={"open"}>
<Tr t={t.ph_open_as_usual} />
</option>
<option value={" "}> <!-- Yes, the value is a single space-->
<Tr t={t.ph_open} />
</option>
</Dropdown>
</label>
{#if $mode === " "}
<div class="flex">
<Tr t={t.opensAt} />
<ToSvelte construct={
new TextField({
value: startValue,
placeholder: "starthour",
htmlType: "time",
}).SetClass("inline-block")
} />
<Tr t={t.openTill} />
<ToSvelte construct={ new TextField({
value: endValue,
placeholder: "endhour",
htmlType: "time",
}).SetClass("inline-block")
} />
</div>
{/if}