Skip to content

Commit 6fce97c

Browse files
author
Miklos Daniel
committed
refactor: state management and types
1 parent cbc5f51 commit 6fce97c

File tree

5 files changed

+140
-255
lines changed

5 files changed

+140
-255
lines changed

src/App.svelte

Lines changed: 101 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -23,150 +23,138 @@
2323
import "@ui5/webcomponents-icons/dist/loan.js";
2424
import "@ui5/webcomponents-icons/dist/globe.js";
2525
import TodoList from "./lib/TodoList.svelte";
26-
import { todos, doneTodos } from "./stores/stores";
27-
import type { TodoItemT } from "./types/TodoItem.type";
26+
import { todoStore } from "./stores/stores.svelte";
2827
import Dialog from "@ui5/webcomponents/dist/Dialog.js";
2928
import Header from "./lib/Header.svelte";
29+
import type { ListSelectionChangeEventDetail } from "@ui5/webcomponents/dist/List.js";
30+
import type { DatePickerChangeEventDetail, DatePickerInputEventDetail } from "@ui5/webcomponents/dist/DatePicker.js";
31+
import { BaseTextArea } from "@ui5/webcomponents/dist/TextArea.js";
32+
import type { ItemDeleteEvent, ItemEditEvent } from "./lib/todoitem.event";
3033
3134
setTheme("sap_horizon");
3235
33-
const dialogHeaderText: string = "Edit Todo";
34-
3536
// Elements
3637
let dialog = $state<Dialog | null>();
37-
let dialogTextArea = $state();
38-
let dialogDatePicker = $state();
3938
40-
// Create ToDo Fields
41-
let itemInputValue;
42-
let itemDateInputValue;
39+
let createTodoFields = $state({
40+
text: "",
41+
date: "",
42+
});
4343
4444
// Edit Dialog fields
45-
let itemEditText: string = $state("");
46-
let itemEditDate: string = $state("");
47-
let selectedEditItem: number;
48-
49-
// Event Handlers
50-
51-
const handleItemInput = (event) => {
52-
itemInputValue = event.target.value;
45+
type DialogFields = {
46+
id: number | null;
47+
text: string;
48+
date: string;
5349
};
5450
55-
const handleDateInput = (event) => {
56-
itemDateInputValue = event.detail.value;
57-
};
51+
let dialogFields = $state<DialogFields>({
52+
id: null,
53+
text: "",
54+
date: "",
55+
});
5856
59-
const handleAdd = (event) => {
60-
const newTodo: TodoItemT = {
61-
id: $todos.length + 1,
62-
desc: itemInputValue,
63-
deadline: itemDateInputValue,
64-
done: false,
65-
};
66-
todos.update((todos) => [...todos, newTodo]);
67-
};
57+
// Event Handlers
6858
69-
const handleDone = (event) => {
70-
const selectedItem = event.detail.selectedItems[0];
71-
const selectedId = selectedItem.getAttribute("data-key");
59+
const handleItemInput = (event: any) => {
60+
console.log(event.target.value);
61+
createTodoFields.text = event.target?.value;
62+
};
7263
73-
const newlySelected = $todos.filter((todo) => {
74-
return selectedId === todo.id.toString();
75-
})[0];
64+
const handleDateInput = (event: CustomEvent<DatePickerInputEventDetail>) => (createTodoFields.date = event.detail.value);
7665
77-
newlySelected.done = true;
66+
const handleAdd = () =>
67+
todoStore.add({
68+
desc: createTodoFields.text,
69+
deadline: createTodoFields.date,
70+
});
7871
79-
doneTodos.update((doneTodos) => [...doneTodos, newlySelected]);
72+
const handleToggleDone = (event: CustomEvent<ListSelectionChangeEventDetail>) => {
73+
const { selectedItems, previouslySelectedItems } = event.detail;
8074
81-
todos.update((todos) =>
82-
todos.filter((todo) => {
83-
return selectedId !== todo.id.toString();
84-
}),
85-
);
86-
};
75+
if (selectedItems.length === previouslySelectedItems.length) {
76+
// No change in selection
77+
return;
78+
}
8779
88-
const handleUndone = (event) => {
89-
const selectedItems = event.detail.selectedItems;
90-
const selectedIds = selectedItems.map((item) => item.getAttribute("data-key"));
91-
92-
const newlyDeselected = $doneTodos
93-
.filter((todo) => {
94-
return selectedIds.indexOf(todo.id.toString()) === -1;
95-
})
96-
.map((item) => {
97-
return { ...item, done: false };
98-
});
99-
100-
doneTodos.update((doneTodos) =>
101-
doneTodos.filter((todo) => {
102-
return selectedIds.indexOf(todo.id.toString()) > -1;
103-
}),
104-
);
105-
106-
todos.update((todos) => [...todos, ...newlyDeselected]);
80+
if (selectedItems.length > previouslySelectedItems.length) {
81+
console.debug("An item was selected");
82+
const newlySelectedItems = selectedItems.filter((item) => !previouslySelectedItems.includes(item));
83+
if (newlySelectedItems.length === 0) {
84+
return;
85+
}
86+
const newlySelectedItemId = newlySelectedItems[0]?.getAttribute("data-key");
87+
if (!newlySelectedItemId) {
88+
return;
89+
}
90+
todoStore.toggleDone(Number(newlySelectedItemId));
91+
} else if (selectedItems.length < previouslySelectedItems.length) {
92+
console.debug("An item was deselected");
93+
94+
const newlyDeselectedItems = previouslySelectedItems.filter((item) => !selectedItems.includes(item));
95+
if (newlyDeselectedItems.length === 0) {
96+
return;
97+
}
98+
const newlyDeselectedItemId = newlyDeselectedItems[0]?.getAttribute("data-key");
99+
if (!newlyDeselectedItemId) {
100+
return;
101+
}
102+
todoStore.toggleDone(Number(newlyDeselectedItemId));
103+
} else {
104+
console.debug("Selection not changed");
105+
}
107106
};
108107
109-
const handleRemove = (event) => {
110-
const filteredTodos = $todos.filter((todo) => todo.id !== event.detail.id);
111-
todos.set(filteredTodos);
112-
113-
const filteredDoneTodos = $doneTodos.filter((todo) => todo.id !== event.detail.id);
114-
doneTodos.set(filteredDoneTodos);
108+
const handleRemove = (event: CustomEvent<ItemDeleteEvent>) => {
109+
todoStore.remove(event.detail.id);
115110
};
116111
117-
const handleEdit = (event) => {
118-
const matchedTodos = $todos.filter((todo) => todo.id === event.detail.id);
112+
const handleEdit = (event: CustomEvent<ItemEditEvent>) => {
113+
const matchedTodo = todoStore.todos.find((todo) => todo.id === event.detail.id);
119114
120-
let todoObj;
121-
if (matchedTodos.length) {
122-
todoObj = matchedTodos[0];
123-
} else {
124-
todoObj = $doneTodos.filter((todo) => todo.id === event.detail.id)[0];
115+
if (!matchedTodo) {
116+
console.warn(`Todo item with id ${event.detail.id} not found.`);
117+
return;
125118
}
126119
127-
itemEditText = todoObj.desc;
128-
itemEditDate = todoObj.deadline;
129-
selectedEditItem = todoObj.id;
120+
dialogFields = {
121+
id: matchedTodo.id,
122+
text: matchedTodo.desc,
123+
date: matchedTodo.deadline,
124+
};
130125
131126
if (dialog) {
132127
dialog.open = true;
133128
}
134129
};
135130
136131
const saveEdits = () => {
137-
const edittedText = dialogTextArea.value;
138-
const edittedDate = dialogDatePicker.value;
139-
140-
todos.update((todos) =>
141-
todos.map((todo) => {
142-
if (todo.id === selectedEditItem) {
143-
todo.desc = edittedText;
144-
todo.deadline = edittedDate;
145-
}
146-
return todo;
147-
}),
148-
);
149-
150-
doneTodos.update((doneTodos) =>
151-
doneTodos.map((todo) => {
152-
if (todo.id === selectedEditItem) {
153-
todo.desc = edittedText;
154-
todo.deadline = edittedDate;
155-
}
156-
return todo;
157-
}),
158-
);
132+
if (!dialogFields.id) {
133+
console.warn("No valid todo id found for editing.");
134+
return;
135+
}
136+
137+
todoStore.update(dialogFields.id, {
138+
desc: dialogFields.text,
139+
deadline: dialogFields.date,
140+
});
159141
160142
if (dialog) {
143+
dialogFields = { id: null, text: "", date: "" };
161144
dialog.open = false;
162145
}
163146
};
164147
165148
const cancelEdits = () => {
166149
if (dialog) {
150+
dialogFields = { id: null, text: "", date: "" };
167151
dialog.open = false;
168152
}
169153
};
154+
155+
// Derived Stores
156+
const doneTodos = $derived(todoStore.todos.filter((t) => t.done));
157+
const undoneTodos = $derived(todoStore.todos.filter((t) => !t.done));
170158
</script>
171159

172160
<main class="app">
@@ -180,30 +168,35 @@
180168
<div class="create-todo-wrapper">
181169
<ui5-input id="add-input" oninput={handleItemInput} placeholder="Type a task..."></ui5-input>
182170
<ui5-date-picker id="date-picker" oninput={handleDateInput} onchange={handleDateInput} format-pattern="dd/MM/yyyy"></ui5-date-picker>
183-
<ui5-button id="add-btn" onclick={handleAdd} design="Emphasized"> Add Todo </ui5-button>
171+
<ui5-button type="button" id="add-btn" onclick={handleAdd} design="Emphasized">Add Todo</ui5-button>
184172
</div>
185173

186174
<section class="list-todo-wrapper">
187-
<ui5-panel class="list-todos-panel" header-text="Incompleted Tasks" collapsed={!$todos.length || undefined}>
188-
<TodoList items={$todos} on:item-edit={handleEdit} on:item-delete={handleRemove} on:selection-change={handleDone} />
175+
<ui5-panel class="list-todos-panel" header-text="Incompleted Tasks" collapsed={!undoneTodos.length || undefined}>
176+
<TodoList items={undoneTodos} on:item-edit={handleEdit} on:item-delete={handleRemove} on:selection-change={handleToggleDone} />
189177
</ui5-panel>
190178

191-
<ui5-panel class="list-todos-panel" header-text="Completed Tasks" collapsed={!$todos.length || undefined}>
192-
<TodoList items={$doneTodos} on:item-edit={handleEdit} on:item-delete={handleRemove} on:selection-change={handleUndone} />
179+
<ui5-panel class="list-todos-panel" header-text="Completed Tasks" collapsed={!doneTodos.length || undefined}>
180+
<TodoList items={doneTodos} on:item-edit={handleEdit} on:item-delete={handleRemove} on:selection-change={handleToggleDone} />
193181
</ui5-panel>
194182
</section>
195183
</section>
196184

197-
<ui5-dialog bind:this={dialog} header-text={dialogHeaderText}>
185+
<ui5-dialog bind:this={dialog} header-text="Edit Todo">
198186
<div class="dialog-content">
199187
<div class="edit-wrapper">
200188
<ui5-label>Title:</ui5-label>
201-
<ui5-textarea class="title-textarea" show-exceeded-text maxlength="24" bind:this={dialogTextArea} value={itemEditText}></ui5-textarea>
189+
<ui5-textarea class="title-textarea" show-exceeded-text maxlength={24} value={dialogFields.text} onchange={(event: any) => (dialogFields.text = event.target.value)}></ui5-textarea>
202190
</div>
203191

204192
<div class="edit-wrapper date-edit-fields">
205193
<ui5-label>Date:</ui5-label>
206-
<ui5-date-picker bind:this={dialogDatePicker} format-pattern="dd/MM/yyyy" value={itemEditDate}></ui5-date-picker>
194+
<ui5-date-picker
195+
bind:this={dialogFields.date}
196+
format-pattern="dd/MM/yyyy"
197+
value={dialogFields.date}
198+
onchange={(event: CustomEvent<DatePickerChangeEventDetail>) => (dialogFields.date = event.detail.value)}
199+
></ui5-date-picker>
207200
</div>
208201
</div>
209202

@@ -212,87 +205,6 @@
212205
<ui5-button class="dialog-footer-btn--save" design="Emphasized" onclick={saveEdits}>Save</ui5-button>
213206
</div>
214207
</ui5-dialog>
215-
216-
<ui5-popover bind:this={themeSettingsPopover} class="app-bar-theming-popover" placement="Bottom" horizontal-align="End" header-text="Theme">
217-
<ui5-list selection-mode="Single" onselection-change={handleThemeChange}>
218-
<ui5-li icon="palette" data-theme="sap_horizon" selected>SAP Horizon Morning</ui5-li>
219-
<ui5-li icon="palette" data-theme="sap_horizon_dark">SAP Horizon Evening</ui5-li>
220-
<ui5-li icon="palette" data-theme="sap_horizon_hcb">SAP Horizon HCB</ui5-li>
221-
<ui5-li icon="palette" data-theme="sap_horizon_hcw">SAP Horizon HCW</ui5-li>
222-
<ui5-li icon="palette" data-theme="sap_fiori_3">SAP Quartz Light</ui5-li>
223-
<ui5-li icon="palette" data-theme="sap_fiori_3_dark">SAP Quartz Dark</ui5-li>
224-
<ui5-li icon="palette" data-theme="sap_fiori_3_hcb">SAP Quartz HCB</ui5-li>
225-
<ui5-li icon="palette" data-theme="sap_fiori_3_hcw">SAP Quartz HCW</ui5-li>
226-
</ui5-list>
227-
</ui5-popover>
228-
229-
<ui5-popover bind:this={profileSettingsPopover} id="profile-pop" class="app-bar-profile-popover" placement="Bottom" horizontal-align="End">
230-
<div class="profile-settings">
231-
<ui5-avatar size="M" initials="JD"></ui5-avatar>
232-
<div class="profile-text">
233-
<ui5-title level="H3">John Doe</ui5-title>
234-
<ui5-label>Svelte Developer</ui5-label>
235-
</div>
236-
</div>
237-
238-
<div class="profile-settings-list">
239-
<ui5-list selection-mode="Single" separators="None" onitem-click={handleProfileSettingsSelect} bind:this={profileSettingsPopover}>
240-
<ui5-li icon="settings" data-key="settings">Settings</ui5-li>
241-
<ui5-li icon="sys-help" data-key="help">Help</ui5-li>
242-
<ui5-li icon="log" data-key="sign-out">Sign out</ui5-li>
243-
</ui5-list>
244-
</div>
245-
</ui5-popover>
246-
247-
<ui5-dialog bind:this={references.dialog.settings} header-text="Profile Settings" draggable>
248-
<div>
249-
<div class="profile-rtl-switch centered">
250-
<div class="profile-rtl-switch-title">
251-
<ui5-label class="profile-rtl-switch-text">RTL</ui5-label>
252-
</div>
253-
<ui5-switch onchange={handleRtlSwitchChange}></ui5-switch>
254-
</div>
255-
</div>
256-
257-
<div class="profile-rtl-switch centered">
258-
<div class="profile-rtl-switch-title">
259-
<ui5-label class="profile-rtl-switch-text">Compact</ui5-label>
260-
</div>
261-
<ui5-switch onchange={handleContentDensitySwitchChange}></ui5-switch>
262-
</div>
263-
264-
<div class="dialog-button">
265-
<ui5-button onclick={handleSettingsDialogCloseButtonClick} design="Emphasized">Close</ui5-button>
266-
</div>
267-
</ui5-dialog>
268-
269-
<ui5-dialog bind:this={references.dialog.help}>
270-
<div slot="header" class="help-header" id="header-title-align">
271-
<ui5-icon name="sys-help"></ui5-icon>
272-
Help
273-
</div>
274-
275-
<div class="help-header" id="header-logo-align">
276-
<img class="app-header-logo" alt="logo" slot="logo" src={logo} />
277-
<ui5-title level="H5">UI5 Web Components Svelte Sample App</ui5-title>
278-
</div>
279-
280-
<p class="help-dialog-text">
281-
<b>Release</b>: b225.20220729335 <br />
282-
<b>Server</b>: pk21443x3132 <br />
283-
<b>Timestamp</b>: 2022-08-18T10:29:03.159+0200 <br />
284-
<b>Company ID</b>: SAP <br />
285-
<b>UI version</b>: SAP Fiori <br />
286-
<b>Edition</b>: Enterprise <br />
287-
<b>Admin version</b>: Svelte Admin <br />
288-
</p>
289-
<hr />
290-
<span class="help-dialog-text">For more information, please visit our <a href="https://github.com/UI5/sample-webcomponents-svelte" target="_blank">documentation</a>.</span>
291-
<p />
292-
<div class="dialog-button">
293-
<ui5-button design="Emphasized" onclick={handleHelpDialogCloseButtonClick}>Close</ui5-button>
294-
</div>
295-
</ui5-dialog>
296208
</main>
297209

298210
<style scoped>

0 commit comments

Comments
 (0)