@pi-spi/app 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -7
- package/assets/icons/qr.png +0 -0
- package/assets/sounds/voice/search_prompt_en.mp3 +0 -0
- package/assets/sounds/voice/search_prompt_fr.mp3 +0 -0
- package/assets/sounds/voice/search_prompt_pt.mp3 +0 -0
- package/example/App.tsx +16 -1
- package/example/app.json +9 -1
- package/lib/module/core/assets.js +1 -0
- package/lib/module/core/assets.js.map +1 -1
- package/lib/module/core/di.js +8 -1
- package/lib/module/core/di.js.map +1 -1
- package/lib/module/core/pi_spi_custom_theme.js +63 -0
- package/lib/module/core/pi_spi_custom_theme.js.map +1 -0
- package/lib/module/core/pi_spi_sdk_config.js +15 -3
- package/lib/module/core/pi_spi_sdk_config.js.map +1 -1
- package/lib/module/core/router.js +3 -0
- package/lib/module/core/router.js.map +1 -1
- package/lib/module/core/routes.js +14 -0
- package/lib/module/core/routes.js.map +1 -1
- package/lib/module/core/storage.js +27 -29
- package/lib/module/core/storage.js.map +1 -1
- package/lib/module/core/theme.js +51 -0
- package/lib/module/core/theme.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/l10n/app_localizations.js.map +1 -1
- package/lib/module/l10n/app_localizations_en.js +24 -1
- package/lib/module/l10n/app_localizations_en.js.map +1 -1
- package/lib/module/l10n/app_localizations_fr.js +24 -1
- package/lib/module/l10n/app_localizations_fr.js.map +1 -1
- package/lib/module/l10n/app_localizations_pt.js +24 -1
- package/lib/module/l10n/app_localizations_pt.js.map +1 -1
- package/lib/module/modules/alias/presentation/pages/alias_page_create_options.js +3 -3
- package/lib/module/modules/alias/presentation/pages/alias_page_create_options.js.map +1 -1
- package/lib/module/modules/alias/presentation/pages/alias_page_otp.js.map +1 -1
- package/lib/module/modules/categorie/presentation/pages/categorie_edit_icon_btn.js +2 -2
- package/lib/module/modules/categorie/presentation/pages/categorie_edit_icon_btn.js.map +1 -1
- package/lib/module/modules/categorie/presentation/pages/categorie_select_widget.js +12 -10
- package/lib/module/modules/categorie/presentation/pages/categorie_select_widget.js.map +1 -1
- package/lib/module/modules/compte/presentation/pages/solde_widget_with_qr.js +14 -9
- package/lib/module/modules/compte/presentation/pages/solde_widget_with_qr.js.map +1 -1
- package/lib/module/modules/home/presentation/pages/home_page.js +41 -2
- package/lib/module/modules/home/presentation/pages/home_page.js.map +1 -1
- package/lib/module/modules/home/presentation/pages/home_tab_compte.js +1 -2
- package/lib/module/modules/home/presentation/pages/home_tab_compte.js.map +1 -1
- package/lib/module/modules/home/presentation/pages/home_tab_compte_more_menu.js +2 -2
- package/lib/module/modules/home/presentation/pages/home_tab_compte_more_menu.js.map +1 -1
- package/lib/module/modules/introduction/presentation/pages/introduction_bar.js +8 -1
- package/lib/module/modules/introduction/presentation/pages/introduction_bar.js.map +1 -1
- package/lib/module/modules/introduction/presentation/pages/introduction_page.js +29 -4
- package/lib/module/modules/introduction/presentation/pages/introduction_page.js.map +1 -1
- package/lib/module/modules/notification/presentation/bloc/notification_bloc.js +11 -4
- package/lib/module/modules/notification/presentation/bloc/notification_bloc.js.map +1 -1
- package/lib/module/modules/notification/presentation/bloc/notification_state.js +7 -1
- package/lib/module/modules/notification/presentation/bloc/notification_state.js.map +1 -1
- package/lib/module/modules/notification/presentation/pages/notification_page_liste.js +6 -2
- package/lib/module/modules/notification/presentation/pages/notification_page_liste.js.map +1 -1
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page.js +2 -2
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page.js.map +1 -1
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_notifications.js +2 -2
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_notifications.js.map +1 -1
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.js +156 -25
- package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.js.map +1 -1
- package/lib/module/modules/profile/presentation/pages/web/profile_web_page.js.map +1 -1
- package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page.js.map +1 -1
- package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page_share.js +2 -2
- package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page_share.js.map +1 -1
- package/lib/module/modules/search/domain/models/fonctionnalite.js +199 -0
- package/lib/module/modules/search/domain/models/fonctionnalite.js.map +1 -0
- package/lib/module/modules/search/presentation/pages/search_fonctionnalites.js +119 -0
- package/lib/module/modules/search/presentation/pages/search_fonctionnalites.js.map +1 -0
- package/lib/module/modules/search/presentation/pages/search_page.js +359 -0
- package/lib/module/modules/search/presentation/pages/search_page.js.map +1 -0
- package/lib/module/modules/search/presentation/pages/search_page_voice_button.js +335 -0
- package/lib/module/modules/search/presentation/pages/search_page_voice_button.js.map +1 -0
- package/lib/module/modules/subscription/presentation/pages/subscription_menu_widget.js +2 -2
- package/lib/module/modules/subscription/presentation/pages/subscription_menu_widget.js.map +1 -1
- package/lib/module/modules/transactions/domain/models/transaction_send/transaction_send_command.js +6 -2
- package/lib/module/modules/transactions/domain/models/transaction_send/transaction_send_command.js.map +1 -1
- package/lib/module/modules/transactions/presentation/bloc/transaction_search/transaction_search_bloc.js +13 -1
- package/lib/module/modules/transactions/presentation/bloc/transaction_search/transaction_search_bloc.js.map +1 -1
- package/lib/module/modules/transactions/presentation/bloc/transaction_search/transaction_search_state.js +7 -1
- package/lib/module/modules/transactions/presentation/bloc/transaction_search/transaction_search_state.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_motif.js +3 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_motif.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_jour_libelle.js +15 -0
- package/lib/module/modules/transactions/presentation/pages/transaction_jour_libelle.js.map +1 -0
- package/lib/module/modules/transactions/presentation/pages/transaction_list_item_widget.js +2 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_list_item_widget.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.js +5 -3
- package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.js +216 -137
- package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_liste.js +8 -3
- package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_liste.js.map +1 -1
- package/lib/module/modules/transactions/presentation/pages/transaction_send/transaction_send_page_options.js +3 -3
- package/lib/module/modules/transactions/presentation/pages/transaction_send/transaction_send_page_options.js.map +1 -1
- package/lib/module/shared/widgets/amount_widget.js +4 -1
- package/lib/module/shared/widgets/amount_widget.js.map +1 -1
- package/lib/module/shared/widgets/input_amount.js.map +1 -1
- package/lib/module/shared/widgets/input_text.js +2 -0
- package/lib/module/shared/widgets/input_text.js.map +1 -1
- package/lib/module/shared/widgets/menu_actions_widget.js +10 -1
- package/lib/module/shared/widgets/menu_actions_widget.js.map +1 -1
- package/lib/module/shared/widgets/pagination_loader_widget.js +29 -0
- package/lib/module/shared/widgets/pagination_loader_widget.js.map +1 -0
- package/lib/typescript/src/core/assets.d.ts +1 -0
- package/lib/typescript/src/core/assets.d.ts.map +1 -1
- package/lib/typescript/src/core/di.d.ts.map +1 -1
- package/lib/typescript/src/core/pi_spi_custom_theme.d.ts +49 -0
- package/lib/typescript/src/core/pi_spi_custom_theme.d.ts.map +1 -0
- package/lib/typescript/src/core/pi_spi_sdk_config.d.ts +15 -2
- package/lib/typescript/src/core/pi_spi_sdk_config.d.ts.map +1 -1
- package/lib/typescript/src/core/router.d.ts +1 -0
- package/lib/typescript/src/core/router.d.ts.map +1 -1
- package/lib/typescript/src/core/routes.d.ts.map +1 -1
- package/lib/typescript/src/core/storage.d.ts +11 -3
- package/lib/typescript/src/core/storage.d.ts.map +1 -1
- package/lib/typescript/src/core/theme.d.ts +19 -0
- package/lib/typescript/src/core/theme.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/l10n/app_localizations.d.ts +46 -0
- package/lib/typescript/src/l10n/app_localizations.d.ts.map +1 -1
- package/lib/typescript/src/l10n/app_localizations_en.d.ts.map +1 -1
- package/lib/typescript/src/l10n/app_localizations_fr.d.ts.map +1 -1
- package/lib/typescript/src/l10n/app_localizations_pt.d.ts.map +1 -1
- package/lib/typescript/src/modules/categorie/presentation/pages/categorie_select_widget.d.ts.map +1 -1
- package/lib/typescript/src/modules/compte/presentation/pages/solde_widget_with_qr.d.ts.map +1 -1
- package/lib/typescript/src/modules/home/presentation/pages/home_page.d.ts.map +1 -1
- package/lib/typescript/src/modules/introduction/presentation/pages/introduction_bar.d.ts.map +1 -1
- package/lib/typescript/src/modules/introduction/presentation/pages/introduction_page.d.ts.map +1 -1
- package/lib/typescript/src/modules/notification/presentation/bloc/notification_bloc.d.ts.map +1 -1
- package/lib/typescript/src/modules/notification/presentation/bloc/notification_state.d.ts +5 -0
- package/lib/typescript/src/modules/notification/presentation/bloc/notification_state.d.ts.map +1 -1
- package/lib/typescript/src/modules/notification/presentation/pages/notification_page_liste.d.ts.map +1 -1
- package/lib/typescript/src/modules/profile/presentation/pages/parametre/profile_parametre_page.d.ts.map +1 -1
- package/lib/typescript/src/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.d.ts.map +1 -1
- package/lib/typescript/src/modules/profile/presentation/pages/web/profile_web_page.d.ts.map +1 -1
- package/lib/typescript/src/modules/search/domain/models/fonctionnalite.d.ts +70 -0
- package/lib/typescript/src/modules/search/domain/models/fonctionnalite.d.ts.map +1 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_fonctionnalites.d.ts +21 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_fonctionnalites.d.ts.map +1 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_page.d.ts +21 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_page.d.ts.map +1 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_page_voice_button.d.ts +29 -0
- package/lib/typescript/src/modules/search/presentation/pages/search_page_voice_button.d.ts.map +1 -0
- package/lib/typescript/src/modules/transactions/domain/models/transaction_send/transaction_send_command.d.ts +1 -1
- package/lib/typescript/src/modules/transactions/domain/models/transaction_send/transaction_send_command.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/bloc/transaction_search/transaction_search_bloc.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/bloc/transaction_search/transaction_search_state.d.ts +5 -0
- package/lib/typescript/src/modules/transactions/presentation/bloc/transaction_search/transaction_search_state.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_motif.d.ts +2 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_motif.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_jour_libelle.d.ts +4 -0
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_jour_libelle.d.ts.map +1 -0
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_list_item_widget.d.ts +2 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_list_item_widget.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.d.ts +5 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.d.ts.map +1 -1
- package/lib/typescript/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_liste.d.ts.map +1 -1
- package/lib/typescript/src/shared/widgets/amount_widget.d.ts +3 -1
- package/lib/typescript/src/shared/widgets/amount_widget.d.ts.map +1 -1
- package/lib/typescript/src/shared/widgets/input_text.d.ts +3 -3
- package/lib/typescript/src/shared/widgets/input_text.d.ts.map +1 -1
- package/lib/typescript/src/shared/widgets/menu_actions_widget.d.ts +5 -1
- package/lib/typescript/src/shared/widgets/menu_actions_widget.d.ts.map +1 -1
- package/lib/typescript/src/shared/widgets/pagination_loader_widget.d.ts +7 -0
- package/lib/typescript/src/shared/widgets/pagination_loader_widget.d.ts.map +1 -0
- package/package.json +49 -35
- package/src/core/assets.ts +1 -0
- package/src/core/di.ts +8 -1
- package/src/core/pi_spi_custom_theme.ts +66 -0
- package/src/core/pi_spi_sdk_config.ts +18 -3
- package/src/core/router.tsx +3 -0
- package/src/core/routes.tsx +15 -0
- package/src/core/storage.ts +30 -22
- package/src/core/theme.ts +53 -0
- package/src/index.ts +2 -1
- package/src/l10n/app_localizations.ts +46 -0
- package/src/l10n/app_localizations_en.ts +23 -0
- package/src/l10n/app_localizations_fr.ts +23 -0
- package/src/l10n/app_localizations_pt.ts +23 -0
- package/src/modules/alias/presentation/pages/alias_page_create_options.tsx +3 -3
- package/src/modules/alias/presentation/pages/alias_page_otp.tsx +2 -2
- package/src/modules/categorie/presentation/pages/categorie_edit_icon_btn.tsx +2 -2
- package/src/modules/categorie/presentation/pages/categorie_select_widget.tsx +13 -9
- package/src/modules/compte/presentation/pages/solde_widget_with_qr.tsx +10 -3
- package/src/modules/home/presentation/pages/home_page.tsx +31 -2
- package/src/modules/home/presentation/pages/home_tab_compte.tsx +1 -1
- package/src/modules/home/presentation/pages/home_tab_compte_more_menu.tsx +2 -2
- package/src/modules/introduction/presentation/pages/introduction_bar.tsx +12 -2
- package/src/modules/introduction/presentation/pages/introduction_page.tsx +20 -2
- package/src/modules/notification/presentation/bloc/notification_bloc.ts +12 -3
- package/src/modules/notification/presentation/bloc/notification_state.ts +11 -1
- package/src/modules/notification/presentation/pages/notification_page_liste.tsx +4 -1
- package/src/modules/profile/presentation/pages/parametre/profile_parametre_page.tsx +5 -2
- package/src/modules/profile/presentation/pages/parametre/profile_parametre_page_notifications.tsx +2 -2
- package/src/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.tsx +95 -15
- package/src/modules/profile/presentation/pages/web/profile_web_page.tsx +3 -2
- package/src/modules/qrcode/presentation/pages/qrcode_alias_page.tsx +2 -2
- package/src/modules/qrcode/presentation/pages/qrcode_alias_page_share.tsx +2 -2
- package/src/modules/search/domain/models/fonctionnalite.ts +217 -0
- package/src/modules/search/presentation/pages/search_fonctionnalites.ts +135 -0
- package/src/modules/search/presentation/pages/search_page.tsx +314 -0
- package/src/modules/search/presentation/pages/search_page_voice_button.tsx +283 -0
- package/src/modules/subscription/presentation/pages/subscription_menu_widget.tsx +2 -2
- package/src/modules/transactions/domain/models/transaction_send/transaction_send_command.ts +6 -2
- package/src/modules/transactions/presentation/bloc/transaction_search/transaction_search_bloc.ts +15 -1
- package/src/modules/transactions/presentation/bloc/transaction_search/transaction_search_state.ts +10 -1
- package/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_motif.tsx +3 -0
- package/src/modules/transactions/presentation/pages/transaction_jour_libelle.ts +17 -0
- package/src/modules/transactions/presentation/pages/transaction_list_item_widget.tsx +3 -1
- package/src/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.tsx +7 -4
- package/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.tsx +204 -101
- package/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_liste.tsx +6 -2
- package/src/modules/transactions/presentation/pages/transaction_send/transaction_send_page_options.tsx +3 -3
- package/src/shared/widgets/amount_widget.tsx +5 -2
- package/src/shared/widgets/input_amount.tsx +2 -2
- package/src/shared/widgets/input_text.tsx +8 -3
- package/src/shared/widgets/menu_actions_widget.tsx +8 -2
- package/src/shared/widgets/pagination_loader_widget.tsx +24 -0
|
@@ -1,80 +1,154 @@
|
|
|
1
1
|
import { MaterialIcons } from '@expo/vector-icons';
|
|
2
|
-
import {
|
|
3
|
-
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
4
4
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
5
5
|
|
|
6
|
-
import { useBloc
|
|
6
|
+
import { useBloc } from '../../../../../core/bloc_react';
|
|
7
7
|
import { AppRouter, useAppRouter } from '../../../../../core/router';
|
|
8
8
|
import { Themer, useTheme } from '../../../../../core/theme';
|
|
9
9
|
import type { AppLocalizations } from '../../../../../l10n/app_localizations';
|
|
10
10
|
import { useAppLocalizations } from '../../../../../l10n/localizations';
|
|
11
|
-
import { TextButton } from '../../../../../shared/material/buttons';
|
|
11
|
+
import { ElevatedButton, TextButton } from '../../../../../shared/material/buttons';
|
|
12
12
|
import { Card } from '../../../../../shared/material/card';
|
|
13
13
|
import { DateFormat } from '../../../../../shared/utils/date_format';
|
|
14
14
|
import { showSelectDateRange } from '../../../../../shared/widgets/select_date_widget';
|
|
15
15
|
import { CategorieSelectWidget } from '../../../../categorie/presentation/pages/categorie_select_widget';
|
|
16
16
|
import { TransactionSens } from '../../../domain/models/transaction';
|
|
17
|
-
import type { TransactionSearchCommand } from '../../../domain/models/transaction_search/transaction_search_command';
|
|
18
17
|
import { TransactionSearchBloc } from '../../bloc/transaction_search/transaction_search_bloc';
|
|
19
18
|
|
|
20
|
-
/**
|
|
19
|
+
/** Sens par défaut : reçus et envoyés */
|
|
20
|
+
const SENS_PAR_DEFAUT: readonly TransactionSens[] = [TransactionSens.credit, TransactionSens.debit];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Filtres de la recherche : plage de dates, sens (reçus / envoyés) et
|
|
24
|
+
* catégories. Les choix sont faits sur un brouillon : ils ne sont reportés
|
|
25
|
+
* sur la commande qu'avec « Appliquer ». Fermer la page les abandonne.
|
|
26
|
+
*/
|
|
21
27
|
export function TransactionSearchPageFilters() {
|
|
22
28
|
const traductions = useAppLocalizations();
|
|
23
29
|
const theme = useTheme();
|
|
24
30
|
const router = useAppRouter();
|
|
25
31
|
const insets = useSafeAreaInsets();
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const [,
|
|
32
|
+
const command = useBloc(TransactionSearchBloc).state.command;
|
|
33
|
+
|
|
34
|
+
// Brouillon des filtres
|
|
35
|
+
const [dateDebut, setDateDebut] = useState(command.filters.dateDebut);
|
|
36
|
+
const [dateFin, setDateFin] = useState(command.filters.dateFin);
|
|
37
|
+
const [sens, setSens] = useState<TransactionSens[]>(() => [...command.filters.sens]);
|
|
38
|
+
const [categories, setCategories] = useState<string[]>(() => [...command.filters.categories]);
|
|
39
|
+
// Change à chaque réinitialisation : les listes de catégories gardent leur
|
|
40
|
+
// sélection en interne, il faut les recréer pour la vider.
|
|
41
|
+
const [versionCategories, setVersionCategories] = useState(0);
|
|
42
|
+
|
|
43
|
+
const estModifie =
|
|
44
|
+
dateDebut != null ||
|
|
45
|
+
dateFin != null ||
|
|
46
|
+
categories.length > 0 ||
|
|
47
|
+
sens.length !== SENS_PAR_DEFAUT.length ||
|
|
48
|
+
!SENS_PAR_DEFAUT.every((s) => sens.includes(s));
|
|
49
|
+
|
|
50
|
+
const reinitialiser = () => {
|
|
51
|
+
setDateDebut(undefined);
|
|
52
|
+
setDateFin(undefined);
|
|
53
|
+
setSens([...SENS_PAR_DEFAUT]);
|
|
54
|
+
setCategories([]);
|
|
55
|
+
setVersionCategories((v) => v + 1);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const appliquer = () => {
|
|
59
|
+
command.filters.dateDebut = dateDebut;
|
|
60
|
+
command.filters.dateFin = dateFin;
|
|
61
|
+
command.filters.sens = [...sens];
|
|
62
|
+
command.filters.categories = [...categories];
|
|
63
|
+
AppRouter.pop(router, { value: command });
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const separateurColor = theme.brightness === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)';
|
|
30
67
|
|
|
31
68
|
return (
|
|
32
69
|
<View style={[styles.flex, { paddingBottom: insets.bottom }]}>
|
|
33
|
-
{/* Barre :
|
|
70
|
+
{/* Barre : fermer, titre, réinitialiser */}
|
|
34
71
|
<View style={styles.bar}>
|
|
35
|
-
<Pressable accessibilityRole="button" hitSlop={12} style={styles.
|
|
36
|
-
<MaterialIcons name="
|
|
72
|
+
<Pressable accessibilityRole="button" hitSlop={12} style={styles.close} onPress={() => AppRouter.pop(router)}>
|
|
73
|
+
<MaterialIcons name="close" size={24} color={theme.colorScheme.onSurface} />
|
|
37
74
|
</Pressable>
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
75
|
+
<Text style={[theme.textTheme.headlineMedium, styles.title]}>{traductions.transactionSearchInputFilterTitle}</Text>
|
|
76
|
+
<TextButton onPress={estModifie ? reinitialiser : undefined}>
|
|
77
|
+
{traductions.transactionSearchInputFilterBtnReinitialiser}
|
|
78
|
+
</TextButton>
|
|
41
79
|
</View>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
{/* Séparateur discret */}
|
|
81
|
+
<View style={[styles.separateur, { backgroundColor: separateurColor }]} />
|
|
82
|
+
|
|
83
|
+
{/* Filtres */}
|
|
84
|
+
<ScrollView style={styles.flex} contentContainerStyle={styles.content}>
|
|
85
|
+
<SectionTitle label={traductions.transactionSearchInputFilterDateTitle} />
|
|
86
|
+
<FiltersDates
|
|
87
|
+
dateDebut={dateDebut}
|
|
88
|
+
dateFin={dateFin}
|
|
89
|
+
traductions={traductions}
|
|
90
|
+
onChange={(debut, fin) => {
|
|
91
|
+
setDateDebut(debut);
|
|
92
|
+
setDateFin(fin);
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
<View style={styles.gap28} />
|
|
96
|
+
{/* Sens de l'opération, puis catégories */}
|
|
97
|
+
<SectionTitle label={traductions.transactionSearchInputFilterCategoriesTitle} />
|
|
98
|
+
<FiltersSens selection={sens} traductions={traductions} separateurColor={separateurColor} onChange={setSens} />
|
|
99
|
+
<View style={styles.gap16} />
|
|
100
|
+
<CategorieSelectWidget
|
|
101
|
+
key={versionCategories}
|
|
102
|
+
selectedCategories={categories}
|
|
103
|
+
onSelectionChanged={(categorie, checked) => {
|
|
104
|
+
setCategories((c) => {
|
|
105
|
+
const autres = c.filter((id) => id !== categorie.id);
|
|
106
|
+
return checked ? [...autres, categorie.id] : autres;
|
|
107
|
+
});
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
</ScrollView>
|
|
111
|
+
|
|
112
|
+
{/* Appliquer */}
|
|
113
|
+
<View style={styles.footer}>
|
|
114
|
+
<ElevatedButton onPress={appliquer}>{traductions.transactionSearchInputFilterBtnAppliquer}</ElevatedButton>
|
|
68
115
|
</View>
|
|
69
116
|
</View>
|
|
70
117
|
);
|
|
71
118
|
}
|
|
72
119
|
|
|
73
|
-
|
|
120
|
+
/** Titre d'une section de filtres */
|
|
121
|
+
function SectionTitle({ label }: { label: string }) {
|
|
122
|
+
const theme = useTheme();
|
|
123
|
+
return <Text style={[theme.textTheme.displayMedium, styles.sectionTitle]}>{label.toUpperCase()}</Text>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Icône dans un carré arrondi */
|
|
127
|
+
function IconBox({ name, color, backgroundColor }: { name: keyof typeof MaterialIcons.glyphMap; color: string; backgroundColor: string }) {
|
|
128
|
+
return (
|
|
129
|
+
<View style={[styles.icon, { backgroundColor }]}>
|
|
130
|
+
<MaterialIcons name={name} size={22} color={color} />
|
|
131
|
+
</View>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function FiltersDates({
|
|
136
|
+
dateDebut,
|
|
137
|
+
dateFin,
|
|
138
|
+
traductions,
|
|
139
|
+
onChange,
|
|
140
|
+
}: {
|
|
141
|
+
dateDebut?: Date;
|
|
142
|
+
dateFin?: Date;
|
|
143
|
+
traductions: AppLocalizations;
|
|
144
|
+
onChange: (debut?: Date, fin?: Date) => void;
|
|
145
|
+
}) {
|
|
74
146
|
const theme = useTheme();
|
|
75
147
|
const router = useAppRouter();
|
|
76
|
-
const format = new DateFormat('d MMM', traductions.localeName);
|
|
77
|
-
const
|
|
148
|
+
const format = new DateFormat('d MMM y', traductions.localeName);
|
|
149
|
+
const estDefinie = dateDebut != null;
|
|
150
|
+
const plage = estDefinie ? (dateFin != null ? `${format.format(dateDebut)} – ${format.format(dateFin)}` : format.format(dateDebut)) : null;
|
|
151
|
+
|
|
78
152
|
return (
|
|
79
153
|
<Card>
|
|
80
154
|
<Pressable
|
|
@@ -82,64 +156,90 @@ function FiltersDates({ command, traductions, onChange }: { command: Transaction
|
|
|
82
156
|
style={styles.tile}
|
|
83
157
|
onPress={async () => {
|
|
84
158
|
const dates = await showSelectDateRange(router, { title: traductions.transactionSearchInputFilterDateSelectTitle });
|
|
85
|
-
|
|
86
|
-
command.filters.dateFin = dates.length === 2 ? dates[1] : undefined;
|
|
87
|
-
onChange();
|
|
159
|
+
onChange(dates[0], dates.length === 2 ? dates[1] : undefined);
|
|
88
160
|
}}
|
|
89
161
|
>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
{
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
162
|
+
{/* Teinté quand le filtre est actif */}
|
|
163
|
+
<IconBox
|
|
164
|
+
name="calendar-month"
|
|
165
|
+
color={estDefinie ? Themer.primaryDark : Themer.neural04Color}
|
|
166
|
+
backgroundColor={estDefinie ? 'rgba(242,169,0,0.15)' : theme.colorScheme.surface}
|
|
167
|
+
/>
|
|
168
|
+
{/* La plage choisie, sinon l'invitation à la choisir */}
|
|
169
|
+
<Text style={[theme.textTheme.headlineSmall, styles.label15, styles.texts]}>
|
|
170
|
+
{plage ?? traductions.transactionSearchInputFilterDateSubTitle}
|
|
171
|
+
</Text>
|
|
172
|
+
{/* Effacer la plage, ou ouvrir le sélecteur */}
|
|
173
|
+
{estDefinie ? (
|
|
174
|
+
<Pressable accessibilityRole="button" hitSlop={8} style={styles.trailing} onPress={() => onChange(undefined, undefined)}>
|
|
175
|
+
<MaterialIcons name="close" size={20} color={Themer.neural03Color} />
|
|
176
|
+
</Pressable>
|
|
177
|
+
) : (
|
|
178
|
+
<MaterialIcons
|
|
179
|
+
style={styles.trailing}
|
|
180
|
+
name={Platform.OS === 'ios' ? 'arrow-forward-ios' : 'arrow-forward'}
|
|
181
|
+
size={Platform.OS === 'ios' ? 18 : 22}
|
|
182
|
+
color={Themer.neural03Color}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
105
185
|
</Pressable>
|
|
106
186
|
</Card>
|
|
107
187
|
);
|
|
108
188
|
}
|
|
109
189
|
|
|
110
|
-
|
|
190
|
+
/** Mêmes icônes et couleurs que dans la liste des transactions. */
|
|
191
|
+
function FiltersSens({
|
|
192
|
+
selection,
|
|
193
|
+
traductions,
|
|
194
|
+
separateurColor,
|
|
195
|
+
onChange,
|
|
196
|
+
}: {
|
|
197
|
+
selection: TransactionSens[];
|
|
198
|
+
traductions: AppLocalizations;
|
|
199
|
+
separateurColor: string;
|
|
200
|
+
onChange: (sens: TransactionSens[]) => void;
|
|
201
|
+
}) {
|
|
111
202
|
const theme = useTheme();
|
|
112
203
|
const items = [
|
|
113
|
-
{
|
|
114
|
-
|
|
204
|
+
{
|
|
205
|
+
sens: TransactionSens.credit,
|
|
206
|
+
icon: 'arrow-forward' as const,
|
|
207
|
+
color: Themer.successColor,
|
|
208
|
+
fond: 'rgba(70,169,61,0.12)',
|
|
209
|
+
label: traductions.transactionSearchInputFilterCategoriesSensRecus,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
sens: TransactionSens.debit,
|
|
213
|
+
icon: 'arrow-back' as const,
|
|
214
|
+
color: theme.colorScheme.error,
|
|
215
|
+
fond: 'rgba(250,90,37,0.12)',
|
|
216
|
+
label: traductions.transactionSearchInputFilterCategoriesSensPayes,
|
|
217
|
+
},
|
|
115
218
|
];
|
|
116
219
|
return (
|
|
117
220
|
<Card>
|
|
118
|
-
{items.map((item) => {
|
|
119
|
-
const checked =
|
|
221
|
+
{items.map((item, index) => {
|
|
222
|
+
const checked = selection.includes(item.sens);
|
|
120
223
|
return (
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
</View>
|
|
141
|
-
<Text style={[theme.textTheme.headlineSmall, styles.label]}>{item.label}</Text>
|
|
142
|
-
</Pressable>
|
|
224
|
+
<View key={item.sens}>
|
|
225
|
+
{/* Séparateur discret */}
|
|
226
|
+
{index > 0 && <View style={[styles.separateur, styles.separateurIndent, { backgroundColor: separateurColor }]} />}
|
|
227
|
+
<Pressable
|
|
228
|
+
accessibilityRole="checkbox"
|
|
229
|
+
accessibilityState={{ checked }}
|
|
230
|
+
style={styles.tile}
|
|
231
|
+
onPress={() => onChange(checked ? selection.filter((s) => s !== item.sens) : [...selection, item.sens])}
|
|
232
|
+
>
|
|
233
|
+
<IconBox name={item.icon} color={item.color} backgroundColor={item.fond} />
|
|
234
|
+
<Text style={[theme.textTheme.headlineSmall, styles.label15, styles.texts]}>{item.label}</Text>
|
|
235
|
+
<MaterialIcons
|
|
236
|
+
style={styles.trailing}
|
|
237
|
+
name={checked ? 'check-box' : 'check-box-outline-blank'}
|
|
238
|
+
size={24}
|
|
239
|
+
color={checked ? theme.colorScheme.primary : Themer.neural02Color}
|
|
240
|
+
/>
|
|
241
|
+
</Pressable>
|
|
242
|
+
</View>
|
|
143
243
|
);
|
|
144
244
|
})}
|
|
145
245
|
</Card>
|
|
@@ -148,16 +248,19 @@ function FiltersSens({ command, traductions, onChange }: { command: TransactionS
|
|
|
148
248
|
|
|
149
249
|
const styles = StyleSheet.create({
|
|
150
250
|
flex: { flex: 1 },
|
|
151
|
-
bar: { flexDirection: 'row', alignItems: 'center',
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
251
|
+
bar: { flexDirection: 'row', alignItems: 'center', paddingTop: 8, paddingLeft: 4, paddingRight: 8 },
|
|
252
|
+
close: { padding: 12 },
|
|
253
|
+
title: { flex: 1, textAlign: 'center' },
|
|
254
|
+
separateur: { height: StyleSheet.hairlineWidth },
|
|
255
|
+
separateurIndent: { marginLeft: 76, marginRight: 16 },
|
|
256
|
+
content: { paddingHorizontal: 16, paddingTop: 24, paddingBottom: 16 },
|
|
257
|
+
sectionTitle: { color: Themer.neural03Color, letterSpacing: 0.6, marginLeft: 4, marginBottom: 10 },
|
|
258
|
+
tile: { flexDirection: 'row', alignItems: 'center', paddingLeft: 16, paddingRight: 8, paddingVertical: 10 },
|
|
259
|
+
icon: { width: 44, height: 44, borderRadius: 14, alignItems: 'center', justifyContent: 'center' },
|
|
157
260
|
texts: { flex: 1, marginHorizontal: 16 },
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
gap16: {
|
|
162
|
-
|
|
261
|
+
label15: { fontSize: 15 },
|
|
262
|
+
trailing: { marginRight: 8 },
|
|
263
|
+
footer: { paddingHorizontal: 16, paddingTop: 8, paddingBottom: 16 },
|
|
264
|
+
gap16: { height: 16 },
|
|
265
|
+
gap28: { height: 28 },
|
|
163
266
|
});
|
|
@@ -5,12 +5,13 @@ import { useBloc, useBlocBuilder } from '../../../../../core/bloc_react';
|
|
|
5
5
|
import { Themer, useTheme } from '../../../../../core/theme';
|
|
6
6
|
import { useAppLocalizations } from '../../../../../l10n/localizations';
|
|
7
7
|
import { Card } from '../../../../../shared/material/card';
|
|
8
|
-
import { DateFormat } from '../../../../../shared/utils/date_format';
|
|
9
8
|
import { AmountWidget } from '../../../../../shared/widgets/amount_widget';
|
|
9
|
+
import { PaginationLoaderWidget } from '../../../../../shared/widgets/pagination_loader_widget';
|
|
10
10
|
import { TransactionSens, type Transaction } from '../../../domain/models/transaction';
|
|
11
11
|
import { TransactionSearchBloc } from '../../bloc/transaction_search/transaction_search_bloc';
|
|
12
12
|
import { TransactionSearchListEvent, TransactionSearchPaginateEvent } from '../../bloc/transaction_search/transaction_search_event';
|
|
13
13
|
import { TransactionSearchListState } from '../../bloc/transaction_search/transaction_search_state';
|
|
14
|
+
import { transactionJourLibelle } from '../transaction_jour_libelle';
|
|
14
15
|
import { TransactionListItemWidget } from '../transaction_list_item_widget';
|
|
15
16
|
import { TransactionListLoadingWidget } from '../transaction_list_loading_widget';
|
|
16
17
|
|
|
@@ -89,11 +90,13 @@ export function TransactionSearchPageListe({
|
|
|
89
90
|
if (command.canLoadMore()) bloc.add(new TransactionSearchPaginateEvent(command.index, command));
|
|
90
91
|
}}
|
|
91
92
|
onEndReachedThreshold={0.2}
|
|
93
|
+
// Chargement de la page suivante
|
|
94
|
+
ListFooterComponent={state.isPaginating ? <PaginationLoaderWidget /> : undefined}
|
|
92
95
|
renderItem={({ item }) => (
|
|
93
96
|
<View>
|
|
94
97
|
{/* Jour et bilan */}
|
|
95
98
|
<View style={styles.header}>
|
|
96
|
-
<Text style={headerStyle}>{
|
|
99
|
+
<Text style={headerStyle}>{transactionJourLibelle(traductions, item.jour)}</Text>
|
|
97
100
|
<AmountWidget montant={item.bilanOperation} style={headerStyle} />
|
|
98
101
|
</View>
|
|
99
102
|
<View style={styles.gap8} />
|
|
@@ -104,6 +107,7 @@ export function TransactionSearchPageListe({
|
|
|
104
107
|
<TransactionListItemWidget
|
|
105
108
|
key={transaction.endToEndId}
|
|
106
109
|
transaction={transaction}
|
|
110
|
+
datePartern="HH:mm"
|
|
107
111
|
onSelect={select != null ? (value: boolean) => select(transaction, value) : undefined}
|
|
108
112
|
isSelected={selectedItems?.some((t) => t.endToEndId === transaction.endToEndId) ?? false}
|
|
109
113
|
/>
|
|
@@ -4,7 +4,7 @@ import { Images } from '../../../../../core/assets';
|
|
|
4
4
|
import { useBloc } from '../../../../../core/bloc_react';
|
|
5
5
|
import { AppRouter, useAppRouter } from '../../../../../core/router';
|
|
6
6
|
import { useAppLocalizations } from '../../../../../l10n/localizations';
|
|
7
|
-
import { MenuActionItem,
|
|
7
|
+
import { MenuActionItem, MenuActionsWidget } from '../../../../../shared/widgets/menu_actions_widget';
|
|
8
8
|
import { AliasBloc } from '../../../../alias/presentation/bloc/alias_bloc';
|
|
9
9
|
import { ContactPI } from '../../../../contacts/domain/contact_pi';
|
|
10
10
|
import { TransactionCanal } from '../../../domain/models/transaction_canal';
|
|
@@ -66,12 +66,12 @@ export function TransactionSendPageOptions({ action }: { action: string }) {
|
|
|
66
66
|
|
|
67
67
|
return (
|
|
68
68
|
<View>
|
|
69
|
-
<
|
|
69
|
+
<MenuActionsWidget items={items} />
|
|
70
70
|
{Platform.OS !== 'web' && (
|
|
71
71
|
<>
|
|
72
72
|
<View style={{ height: 5 }} />
|
|
73
73
|
{/* Nouveau contact */}
|
|
74
|
-
<
|
|
74
|
+
<MenuActionsWidget
|
|
75
75
|
items={[
|
|
76
76
|
new MenuActionItem(
|
|
77
77
|
Images.iconTransactionSendByNewContact,
|
|
@@ -22,6 +22,7 @@ export function AmountWidget({
|
|
|
22
22
|
surfixText,
|
|
23
23
|
style,
|
|
24
24
|
numberOfLines,
|
|
25
|
+
adjustsFontSizeToFit,
|
|
25
26
|
}: {
|
|
26
27
|
montant: number | null | undefined;
|
|
27
28
|
sign?: string;
|
|
@@ -29,6 +30,8 @@ export function AmountWidget({
|
|
|
29
30
|
surfixText?: string;
|
|
30
31
|
style?: TextStyle;
|
|
31
32
|
numberOfLines?: number;
|
|
33
|
+
/** Réduit la police pour que le texte tienne dans la largeur disponible (avec [numberOfLines]). */
|
|
34
|
+
adjustsFontSizeToFit?: boolean;
|
|
32
35
|
}) {
|
|
33
36
|
const locale = useAppLocalizations().localeName;
|
|
34
37
|
const configBloc = useBloc(ConfigBloc);
|
|
@@ -45,7 +48,7 @@ export function AmountWidget({
|
|
|
45
48
|
const text = `${prefix}${value}${suffix}`;
|
|
46
49
|
if (displayAmount) {
|
|
47
50
|
return (
|
|
48
|
-
<Text numberOfLines={numberOfLines} style={style}>
|
|
51
|
+
<Text numberOfLines={numberOfLines} adjustsFontSizeToFit={adjustsFontSizeToFit} style={style}>
|
|
49
52
|
{text}
|
|
50
53
|
</Text>
|
|
51
54
|
);
|
|
@@ -56,7 +59,7 @@ export function AmountWidget({
|
|
|
56
59
|
// transparent, d'où le flou porté par la vue.
|
|
57
60
|
return (
|
|
58
61
|
<View style={styles.hidden}>
|
|
59
|
-
<Text numberOfLines={numberOfLines} style={[style, styles.transparent]}>
|
|
62
|
+
<Text numberOfLines={numberOfLines} adjustsFontSizeToFit={adjustsFontSizeToFit} style={[style, styles.transparent]}>
|
|
60
63
|
{text}
|
|
61
64
|
</Text>
|
|
62
65
|
</View>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRef, useState, type ReactNode } from 'react';
|
|
2
|
-
import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
2
|
+
import { Pressable, StyleSheet, Text, TextInput, View, type TextInputInstance } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { Themer, useTheme } from '../../core/theme';
|
|
5
5
|
import { useAppLocalizations } from '../../l10n/localizations';
|
|
@@ -60,7 +60,7 @@ export function InputAmount({
|
|
|
60
60
|
const traductions = useAppLocalizations();
|
|
61
61
|
const locale = traductions.localeName;
|
|
62
62
|
const input = theme.inputDecorationTheme;
|
|
63
|
-
const ref = useRef<
|
|
63
|
+
const ref = useRef<TextInputInstance>(null);
|
|
64
64
|
const [focused, setFocused] = useState(false);
|
|
65
65
|
const [text, setText] = useState(() => formatSaisie(value ?? '', locale));
|
|
66
66
|
const hasError = messageError != null && messageError.length > 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { forwardRef, useRef, useState, type ReactNode } from 'react';
|
|
2
|
-
import { StyleSheet, Text, TextInput, View, type KeyboardTypeOptions, type ReturnKeyTypeOptions } from 'react-native';
|
|
1
|
+
import { forwardRef, useRef, useState, type ForwardRefExoticComponent, type ReactNode, type RefAttributes } from 'react';
|
|
2
|
+
import { StyleSheet, Text, TextInput, View, type KeyboardTypeOptions, type ReturnKeyTypeOptions, type TextInputInstance } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useTheme } from '../../core/theme';
|
|
5
5
|
import { FloatingLabel } from './floating_label';
|
|
@@ -37,7 +37,12 @@ const HEIGHT = 56;
|
|
|
37
37
|
* comme un `TextField` Material (le texte d'aide n'apparaît qu'au focus
|
|
38
38
|
* quand il y a un label), et message d'erreur sous le champ.
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
// Type annoté : celui inféré depuis React Native 0.88 n'est pas exportable
|
|
41
|
+
// dans les déclarations du package.
|
|
42
|
+
export const CustomTextInput: ForwardRefExoticComponent<CustomTextInputProps & RefAttributes<TextInputInstance>> = forwardRef<
|
|
43
|
+
TextInputInstance,
|
|
44
|
+
CustomTextInputProps
|
|
45
|
+
>(function CustomTextInput(props, ref) {
|
|
41
46
|
const theme = useTheme();
|
|
42
47
|
const input = theme.inputDecorationTheme;
|
|
43
48
|
const [focused, setFocused] = useState(false);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Image } from 'expo-image';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
2
3
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
4
|
|
|
4
5
|
import { useTheme } from '../../core/theme';
|
|
@@ -7,21 +8,24 @@ import { Card } from '../material/card';
|
|
|
7
8
|
export class MenuActionItem {
|
|
8
9
|
readonly iconSize?: number;
|
|
9
10
|
readonly color?: string;
|
|
11
|
+
/** Élément affiché à droite de la ligne (ex. une flèche). */
|
|
12
|
+
readonly trailing?: ReactNode;
|
|
10
13
|
|
|
11
14
|
constructor(
|
|
12
15
|
readonly icon: number,
|
|
13
16
|
readonly title: string,
|
|
14
17
|
readonly subtitle: string | null | undefined,
|
|
15
18
|
readonly action: () => void,
|
|
16
|
-
options: { iconSize?: number; color?: string } = {},
|
|
19
|
+
options: { iconSize?: number; color?: string; trailing?: ReactNode } = {},
|
|
17
20
|
) {
|
|
18
21
|
this.iconSize = options.iconSize;
|
|
19
22
|
this.color = options.color;
|
|
23
|
+
this.trailing = options.trailing;
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/** Liste d'actions (icône, titre, sous-titre) dans une carte, comme des `ListTile` Material. */
|
|
24
|
-
export function
|
|
28
|
+
export function MenuActionsWidget({ items }: { items: MenuActionItem[] }) {
|
|
25
29
|
const theme = useTheme();
|
|
26
30
|
return (
|
|
27
31
|
<Card>
|
|
@@ -45,6 +49,7 @@ export function MenuActionsWiget({ items }: { items: MenuActionItem[] }) {
|
|
|
45
49
|
<Text style={[theme.textTheme.headlineSmall, item.color ? { color: item.color } : null]}>{item.title}</Text>
|
|
46
50
|
{item.subtitle != null && <Text style={theme.textTheme.displaySmall}>{item.subtitle}</Text>}
|
|
47
51
|
</View>
|
|
52
|
+
{item.trailing != null && <View style={styles.trailing}>{item.trailing}</View>}
|
|
48
53
|
</Pressable>
|
|
49
54
|
))}
|
|
50
55
|
</Card>
|
|
@@ -55,4 +60,5 @@ const styles = StyleSheet.create({
|
|
|
55
60
|
tile: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 8, minHeight: 72 },
|
|
56
61
|
leading: { width: 45, height: 45, borderRadius: 14, alignItems: 'center', justifyContent: 'center', marginRight: 16 },
|
|
57
62
|
texts: { flex: 1 },
|
|
63
|
+
trailing: { marginLeft: 16 },
|
|
58
64
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ActivityIndicator, Platform, StyleSheet, View } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { useTheme } from '../../core/theme';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Petit loader affiché en bas d'une liste pendant le chargement de la page
|
|
7
|
+
* suivante (pagination). Sur iOS, le loader natif garde sa couleur
|
|
8
|
+
* système ; sur le web et Android, il prend la couleur primaire.
|
|
9
|
+
*/
|
|
10
|
+
export function PaginationLoaderWidget() {
|
|
11
|
+
const theme = useTheme();
|
|
12
|
+
return (
|
|
13
|
+
<View style={styles.container}>
|
|
14
|
+
<ActivityIndicator
|
|
15
|
+
size="small"
|
|
16
|
+
color={Platform.OS === 'ios' ? undefined : theme.colorScheme.primary}
|
|
17
|
+
/>
|
|
18
|
+
</View>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const styles = StyleSheet.create({
|
|
23
|
+
container: { paddingVertical: 16, alignItems: 'center', justifyContent: 'center' },
|
|
24
|
+
});
|