tallyweb_frontend/pages/
preferences.rs

1#![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}