tallyweb_frontend/pages/
preferences.rs1#![allow(unused_braces)]
2use components::{MessageJar, SavingMessage, Slider};
3use leptos::*;
4use leptos_router::{ActionForm, A};
5use web_sys::{Event, SubmitEvent};
6
7stylance::import_style!(
8 #[allow(dead_code)]
9 style,
10 "../../style/edit.module.scss"
11);
12
13use super::*;
14
15#[component]
16pub fn PreferencesWindow() -> impl IntoView {
17 let preferences = expect_context::<RwSignal<Preferences>>();
18 let message = expect_context::<MessageJar>();
19 let session = expect_context::<RwSignal<UserSession>>();
20 let pref_resource = expect_context::<PrefResource>();
21 let screen = expect_context::<Screen>();
22
23 let action = create_server_action::<api::SavePreferences>();
24
25 let (accent_color, set_accent_color) = create_slice(
26 preferences,
27 |pref| pref.accent_color.0.clone(),
28 |pref, new| pref.accent_color.0 = new,
29 );
30
31 let on_change = move |ev: Event| {
32 let color = event_target_value(&ev);
33 if color.is_empty() {
34 ev.prevent_default()
35 }
36 set_accent_color(color)
37 };
38
39 let on_submit = move |ev: SubmitEvent| {
40 ev.prevent_default();
41
42 action.dispatch(api::SavePreferences {
43 session_user_uuid: session.get_untracked().user_uuid,
44 session_username: session.get_untracked().username,
45 session_token: session.get_untracked().token,
46 preferences: preferences.get_untracked(),
47 });
48
49 let msg_key = message
50 .with_handle()
51 .without_timeout()
52 .set_msg_view(SavingMessage);
53
54 create_effect(move |_| match action.value().get() {
55 Some(Ok(_)) => {
56 message.fade_out(msg_key);
57 action.value().set_untracked(None)
58 }
59 Some(Err(err)) => {
60 message.fade_out(msg_key);
61 message.set_err(AppError::from(err));
62 action.value().set_untracked(None)
63 }
64 None => {}
65 });
66 };
67
68 let on_default_checked = move |_: Event| {
69 preferences.update(|p| p.use_default_accent_color = !p.use_default_accent_color);
70 preferences.update(|p| p.accent_color.set_user(&session.get_untracked()))
71 };
72
73 let on_separator_checked =
74 move |_: Event| preferences.update(|p| p.show_separator = !p.show_separator);
75
76 let on_multi_checked = move |_: Event| preferences.update(|p| p.multi_select = !p.multi_select);
77
78 let undo_changes = move |_| pref_resource.refetch();
79
80 let form_style = move || {
81 stylance::classes!(
82 style::form,
83 match (screen.style)() {
84 ScreenStyle::Portrait => Some(style::portrait),
85 ScreenStyle::Small => Some(style::small),
86 ScreenStyle::Big => Some(style::big),
87 }
88 )
89 };
90
91 view! {
92 <elements::Navbar has_sidebar=false></elements::Navbar>
93 <h1 style:color="white" style:padding="12px 48px">
94 Settings
95 </h1>
96 <div style:display="flex" style:height="100%" style:justify-content="center">
97 <edit-form class=form_style>
98 <ActionForm action=action on:submit=on_submit>
99 <SessionFormInput session />
100 <table class=style::content>
101 <tr class=style::row>
102 <td>
103 <label for="use-default-color" class="title">
104 Use Default Accent Color
105 </label>
106 </td>
107 <td>
108 <Slider
109 checked=preferences.get_untracked().use_default_accent_color
110 attr:name="preferences[use_default_accent_color]"
111 attr:id="use-default-color"
112 on:change=on_default_checked
113 />
114 </td>
115 </tr>
116
117 <tr class=style::row>
118 <td>
119 <label for="accent-color" class="title">
120 Accent Color
121 </label>
122 </td>
123 <td>
124 <input
125 type="color"
126 name="preferences[accent_color]"
127 id="accent-color"
128 class="edit"
129 on:input=on_change
130 disabled=move || preferences().use_default_accent_color
131 value=accent_color
132 prop:value=accent_color
133 />
134 </td>
135 </tr>
136
137 <SaveOnPause />
138
139 <tr>
140 <td colspan="2">
141 <hr />
142 </td>
143 </tr>
144
145 <tr class=style::row>
146 <td>
147 <label for="show-separator" class="title">
148 Show Treeview Separator
149 </label>
150 </td>
151 <td>
152 <Slider
153 checked=preferences.get_untracked().show_separator
154 attr:name="preferences[show_separator]"
155 attr:id="show-separator"
156 on:change=on_separator_checked
157 />
158 </td>
159 </tr>
160
161 <tr class=style::row>
162 <td>
163 <label for="multi-select" class="title">
164 Use Multi Select (experimental)
165 </label>
166 </td>
167 <td>
168 <Slider
169 checked=preferences.get_untracked().multi_select
170 attr:name="preferences[multi_select]"
171 attr:id="multi-select"
172 on:change=on_multi_checked
173 />
174 </td>
175 </tr>
176
177 <tr>
178 <td colspan="2">
179 <hr />
180 </td>
181 </tr>
182
183 <tr class=style::row>
184 <td>
185 <span for="change-username" class="title">
186 Change Username
187 </span>
188 </td>
189 <td>
190 <A class=style::edit href="/change-username">
191 <i class="fa-solid fa-arrow-right"></i>
192 </A>
193 </td>
194 </tr>
195
196 <tr class=style::row>
197 <td>
198 <span class="title">Change Password</span>
199 </td>
200 <td>
201 <A class=style::edit href="/change-password">
202 <i class="fa-solid fa-arrow-right"></i>
203 </A>
204 </td>
205 </tr>
206 </table>
207
208 <action-buttons
209 style:display="flex"
210 style:justify-content="space-between"
211 class=move || {
212 stylance::classes!(
213 style::action_buttons, match (screen.style) () {
214 ScreenStyle::Portrait => Some(style::fixed), ScreenStyle::Small =>
215 None, ScreenStyle::Big => None, }
216 )
217 }
218 >
219
220 <action-start></action-start>
221 <action-end>
222 <button type="button" on:click=undo_changes>
223 <span>Undo</span>
224 </button>
225 <button type="submit" class=style::confirm>
226 <span>Save</span>
227 </button>
228 </action-end>
229 </action-buttons>
230 </ActionForm>
231 </edit-form>
232 </div>
233 }
234}
235
236#[component]
237fn SaveOnPause() -> impl IntoView {
238 let preferences = expect_context::<RwSignal<Preferences>>();
239 let (checked, set_checked) =
240 create_slice(preferences, |p| p.save_on_pause, |p, c| p.save_on_pause = c);
241 let on_change = move |_| set_checked(!checked());
242
243 view! {
244 <tr class=style::row>
245 <td>
246 <label for="save-on-pause">Save on pause</label>
247 </td>
248 <td>
249 <Slider
250 checked
251 attr:name="preferences[save_on_pause]"
252 attr:id="save-on-pause"
253 on:change=on_change
254 />
255 </td>
256 </tr>
257 }
258}