cic-kit 0.0.8 → 0.0.9
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 +38 -78
- package/dist/cic-kit.css +1 -1
- package/dist/cmp/Btn/shareLink.d.ts +6 -0
- package/dist/cmp/Btn/typeBtn.d.ts +3 -0
- package/dist/cmp/cicKitStore.d.ts +5 -0
- package/dist/cmp/clone/clone.d.ts +1 -0
- package/dist/cmp/firebase/FirestoreModel.d.ts +81 -0
- package/dist/cmp/firebase/FirestoreStore.d.ts +116 -0
- package/dist/cmp/firebase/firebase.d.ts +27 -0
- package/dist/cmp/firebase/middlewareCatchCall.d.ts +1 -0
- package/dist/cmp/firebase/useStoreWatch.d.ts +9 -0
- package/dist/cmp/form-validator/FormValidator.d.ts +88 -0
- package/dist/cmp/form-validator/InputValueParser.d.ts +25 -0
- package/dist/cmp/form-validator/Validator.d.ts +28 -0
- package/dist/cmp/input/Gender/Gender.d.ts +1 -0
- package/dist/cmp/input/PhoneNumber/PhoneNumber.d.ts +2 -0
- package/dist/cmp/localStorage/LS.d.ts +32 -0
- package/dist/cmp/network/network.d.ts +3 -0
- package/dist/cmp/notification/pushMsg.d.ts +18 -0
- package/dist/cmp/timestamp/parseTimestamp.d.ts +8 -0
- package/dist/cmp/toast/Toast.d.ts +52 -0
- package/dist/cmp/toast/toastController.d.ts +21 -0
- package/dist/index.cjs +38 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.mjs +20436 -81
- package/dist/models/User.d.ts +59 -0
- package/package.json +2 -1
- package/scss/_style.scss +3 -1
- package/src/styles/partials/_font_icon.scss +1 -14
- package/src/vue-shim.d.ts +2 -2
- package/src/styles/fonts/Noto_Color_Emoji/NotoColorEmoji-Regular.ttf +0 -0
- package/src/styles/fonts/Noto_Color_Emoji/OFL.txt +0 -93
package/README.md
CHANGED
|
@@ -2,29 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
`cic-kit` è un piccolo kit di componenti e stili per **Vue 3**, pensato per essere riutilizzato tra più progetti.
|
|
4
4
|
|
|
5
|
-
Attualmente esporta:
|
|
6
|
-
- ✅ un componente Vue (`BtnCmp`)
|
|
7
|
-
- ✅ uno stylesheet (`style.css`) con utility, font e override
|
|
8
|
-
- ❌ **non** include Bootstrap o Vue Router internamente (usa quelli del progetto consumer)
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Installazione
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install cic-kit
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
> Il progetto che usa `cic-kit` deve avere già installati:
|
|
19
|
-
> - `vue`
|
|
20
|
-
> - `vue-router`
|
|
21
|
-
> - `bootstrap`
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
5
|
## Peer Dependencies
|
|
26
6
|
|
|
27
|
-
|
|
7
|
+
Il progetto che usa `cic-kit` deve avere già installati:
|
|
28
8
|
|
|
29
9
|
```json
|
|
30
10
|
{
|
|
@@ -34,29 +14,53 @@ Questo pacchetto **non porta con sé** queste dipendenze, ma usa quelle del prog
|
|
|
34
14
|
}
|
|
35
15
|
```
|
|
36
16
|
|
|
37
|
-
Questa è una scelta intenzionale per evitare duplicazioni e conflitti di stile.
|
|
38
|
-
|
|
39
17
|
---
|
|
40
18
|
|
|
41
|
-
##
|
|
19
|
+
## Installazione
|
|
42
20
|
|
|
43
|
-
|
|
21
|
+
dopo aver installato le peer Dependencies
|
|
44
22
|
|
|
45
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npm install cic-kit
|
|
25
|
+
```
|
|
46
26
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
27
|
+
poi importa lo style su un scss con
|
|
28
|
+
|
|
29
|
+
```scss
|
|
30
|
+
@use "cic-kit/style";
|
|
50
31
|
```
|
|
51
32
|
|
|
52
|
-
|
|
33
|
+
❌ **non** include Bootstrap internamente bisogna importarlo prima con `@use "bootstrap/scss/bootstrap"`;
|
|
34
|
+
|
|
35
|
+
## Style
|
|
36
|
+
|
|
37
|
+
> `_style.scss` include:
|
|
38
|
+
>
|
|
39
|
+
> - regolre di reset
|
|
53
40
|
> - font custom (Material Symbols, emoji, ecc.)
|
|
54
|
-
> - utility CSS
|
|
55
41
|
> - override delle classi Bootstrap
|
|
42
|
+
> - utility CSS
|
|
56
43
|
|
|
57
|
-
|
|
44
|
+
## Componenti
|
|
45
|
+
|
|
46
|
+
Tra i componenti ci sono file di utility .ts e componenti .vue che possono utilizzare store globali basati su reactive() per controllarli
|
|
47
|
+
|
|
48
|
+
#### BtnCmp
|
|
49
|
+
|
|
50
|
+
Button Bootstrap con varianti, icona, loading e navigazione router.
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
| prop | default | type | utilizzo |
|
|
53
|
+
| ---------- | -------- | ----------------------------------------------------------------------------------------------- | --------------------------- |
|
|
54
|
+
| `variant` | `solid` | `"solid" \| "outline" \| "ghost" \| "link"` | stile del bottone |
|
|
55
|
+
| `color` | `dark` | `"primary" \| "secondary" \| "success" \| "danger" \| "warning" \| "info" \| "light" \| "dark"` | cambia colore Bootstrap |
|
|
56
|
+
| `size` | — | `"sm" \| "lg"` | dimensione Bootstrap |
|
|
57
|
+
| `block` | `false` | `boolean` | full width (`w-100`) |
|
|
58
|
+
| `disabled` | `false` | `boolean` | disabilita click |
|
|
59
|
+
| `type` | `button` | `"button" \| "submit" \| "reset"` | tipo HTML button |
|
|
60
|
+
| `to` | — | `RouteLocationRaw` | naviga con `router.push` |
|
|
61
|
+
| `loading` | `false` | `boolean` | mostra spinner e disabilita |
|
|
62
|
+
| `icon` | — | `string` | icona Material Symbols |
|
|
63
|
+
| `share` | — | `ShareLink` | condivide link al click |
|
|
60
64
|
|
|
61
65
|
```vue
|
|
62
66
|
<script setup lang="ts">
|
|
@@ -64,50 +68,6 @@ import { BtnCmp } from "cic-kit";
|
|
|
64
68
|
</script>
|
|
65
69
|
|
|
66
70
|
<template>
|
|
67
|
-
<BtnCmp
|
|
71
|
+
<BtnCmp color="primary">Salva</BtnCmp>
|
|
68
72
|
</template>
|
|
69
73
|
```
|
|
70
|
-
|
|
71
|
-
Il componente utilizza `vue-router`, quindi l’app deve avere un router configurato.
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## Font e asset
|
|
76
|
-
|
|
77
|
-
I font sono inclusi nello stylesheet del pacchetto.
|
|
78
|
-
Durante la build possono essere:
|
|
79
|
-
- **inlined** (base64 nel CSS), oppure
|
|
80
|
-
- **copiati come asset** (a seconda della configurazione di build)
|
|
81
|
-
|
|
82
|
-
In entrambi i casi **non è richiesta alcuna configurazione aggiuntiva** nel progetto consumer.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Filosofia del pacchetto
|
|
87
|
-
|
|
88
|
-
- 🧩 Componenti piccoli e riutilizzabili
|
|
89
|
-
- 🎨 Stili centralizzati e condivisi
|
|
90
|
-
- 📦 Nessuna dipendenza “hardcoded”
|
|
91
|
-
- 🔌 Massima integrazione con il progetto consumer
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Sviluppo
|
|
96
|
-
|
|
97
|
-
Il pacchetto è pensato per essere usato insieme a un progetto di test/sandbox separato.
|
|
98
|
-
|
|
99
|
-
Build della libreria:
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
npm run build
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Prima della pubblicazione è consigliato testare il pacchetto con:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
npm pack
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
e installare il `.tgz` in un progetto Vue reale.
|
|
112
|
-
|
|
113
|
-
---
|
package/dist/cic-kit.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.spinner-border[data-v-
|
|
1
|
+
.spinner-border[data-v-2280ac85]{vertical-align:middle}.btn-ms-link[data-v-2280ac85]{background-color:transparent!important;border:none;color:var(--bs-btn-color)!important}.btn-ms-link[data-v-2280ac85]:hover{text-decoration:underline}.hideAfter[data-v-2280ac85]:after{display:none}.toast-wrapper[data-v-821bd999]{position:fixed;bottom:20px;right:20px;display:flex;flex-direction:column;gap:6px;z-index:999999}.toast-card[data-v-821bd999]{width:330px;min-height:80px;border-radius:8px;padding:10px 12px;background-color:#fff;box-shadow:0 8px 24px #00000026;display:flex;align-items:center;justify-content:center;gap:12px;cursor:default;transition:all .3s ease,transform .3s ease;overflow:hidden;opacity:1}.toast-card .icon-container[data-v-821bd999]{width:35px;height:35px;display:flex;justify-content:center;align-items:center;border-radius:50%;flex-shrink:0;transition:all .3s ease}.toast-card .message-text[data-v-821bd999]{font-size:17px;font-weight:700}.toast-card .sub-text[data-v-821bd999]{color:#555;font-size:14px}.toast-card .cross-icon[data-v-821bd999]{width:18px;height:18px;color:#555;cursor:pointer;flex-shrink:0}.toast-card[data-v-821bd999]:not(.expanded){min-height:40px;max-height:40px;padding-top:6px;padding-bottom:6px;opacity:.7}.toast-card:not(.expanded) .icon-container[data-v-821bd999]{width:18px;height:18px}.toast-card:not(.expanded) .message-text[data-v-821bd999]{font-size:14px}.toast-card:not(.expanded) .sub-content[data-v-821bd999]{display:none}.toast-card:not(.expanded) .cross-icon[data-v-821bd999]{width:14px;height:14px}.toast-fade-enter-from[data-v-821bd999],.toast-fade-leave-to[data-v-821bd999]{opacity:0;transform:translateY(20px)}.toast-fade-enter-active[data-v-821bd999],.toast-fade-leave-active[data-v-821bd999]{transition:all .3s ease}.message-text-container[data-v-821bd999]{flex-grow:1}.toast-card.info[data-v-821bd999]{border-right:5px solid var(--bs-info)}.toast-card.info .icon-container[data-v-821bd999]{color:var(--bs-info)}.toast-card.success[data-v-821bd999]{border-right:5px solid var(--bs-success)}.toast-card.success .icon-container[data-v-821bd999]{color:var(--bs-success)}.toast-card.warning[data-v-821bd999]{border-right:5px solid var(--bs-warning)}.toast-card.warning .icon-container[data-v-821bd999]{color:var(--bs-warning)}.toast-card.error[data-v-821bd999]{border-right:5px solid var(--bs-danger)}.toast-card.error .icon-container[data-v-821bd999]{color:var(--bs-danger)}.toast-card.primary[data-v-821bd999]{border-right:5px solid var(--bs-primary)}.toast-card.primary .icon-container[data-v-821bd999]{color:var(--bs-primary)}.toast-card.secondary[data-v-821bd999]{border-right:5px solid var(--bs-secondary)}.toast-card.secondary .icon-container[data-v-821bd999]{color:var(--bs-secondary)}.prefix-width[data-v-d70bf135]{width:60px}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type BtnVariant = "solid" | "outline" | "ghost" | "link";
|
|
2
|
+
export type BtnColor = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark";
|
|
3
|
+
export type IconGoogle = "search" | "home" | "menu" | "close" | "settings" | "send" | "add" | "remove" | "delete" | "star" | "star_half" | "arrow_forward_ios" | "arrow_back_ios" | "logout" | "more_vert" | "favorite" | "login" | "radio_button_unchecked" | "radio_button_checked" | "bolt" | "block" | "sync" | "share" | "ios_share" | "upload" | "alternate_email" | "account_circle" | "manage_accounts" | "visibility" | "visibility_off" | "language" | "support" | "mail" | "call" | "notifications" | "link" | "person_search" | "edit" | "photo_camera" | "image" | "circle" | "payments" | "credit_card" | "database" | "shopping_bag" | "account_balance" | "savings" | "qr_code" | "euro" | "wallet" | "payment_arrow_down" | "location_on" | "map" | "fastfood";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function clone<U>(o: U): U;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DocumentReference, Timestamp } from 'firebase/firestore';
|
|
2
|
+
type FirestoreStore_delete = {
|
|
3
|
+
delete: (id: string, opts?: Omit<OptionFireModel, 'touchUpdate'>) => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export declare function fireDebugLog(collectionPath: string, icons: string, type: string, ...args: unknown[]): void;
|
|
6
|
+
export type Timestampble = {
|
|
7
|
+
createdAt: Timestamp;
|
|
8
|
+
updatedAt: Timestamp;
|
|
9
|
+
deleteAt: Timestamp | null;
|
|
10
|
+
};
|
|
11
|
+
export type OptionFireModel = {
|
|
12
|
+
offlineAllow?: boolean;
|
|
13
|
+
touchUpdate?: boolean;
|
|
14
|
+
localSet?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare const optionFireModelDefault: OptionFireModel;
|
|
17
|
+
export declare abstract class FirestoreModel<T extends {
|
|
18
|
+
id: string;
|
|
19
|
+
}> {
|
|
20
|
+
id: string;
|
|
21
|
+
createdAt: Timestamp;
|
|
22
|
+
updatedAt: Timestamp;
|
|
23
|
+
deleteAt: Timestamp | null;
|
|
24
|
+
protected constructor(data: T & Partial<Timestampble>);
|
|
25
|
+
static collectionName?: string;
|
|
26
|
+
private debugLog;
|
|
27
|
+
/**
|
|
28
|
+
* Facoltativo: i model figli possono override-are questo metodo
|
|
29
|
+
* per fornire la path dinamica di collezione (es. subcollection).
|
|
30
|
+
* Esempio: "debits/{parentId}/transitions"
|
|
31
|
+
*/
|
|
32
|
+
protected getCollectionPath?(): string;
|
|
33
|
+
protected localStorageKey?(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Ritorna la DocumentReference calcolando:
|
|
36
|
+
* - se il model ha getCollectionPath(): la usa
|
|
37
|
+
* - altrimenti usa la static collectionName.
|
|
38
|
+
*/
|
|
39
|
+
get ref(): DocumentReference;
|
|
40
|
+
abstract toData(): T;
|
|
41
|
+
/**
|
|
42
|
+
* GET singolo documento.
|
|
43
|
+
*/
|
|
44
|
+
static get<U extends FirestoreModel<T>, T extends {
|
|
45
|
+
id: string;
|
|
46
|
+
}>(this: {
|
|
47
|
+
new (data: T): U;
|
|
48
|
+
collectionName?: string;
|
|
49
|
+
}, id: string, opts?: {
|
|
50
|
+
collectionPath?: string;
|
|
51
|
+
localSet?: boolean;
|
|
52
|
+
}): Promise<U | undefined>;
|
|
53
|
+
static cleanDataAAA(data: any): {
|
|
54
|
+
[k: string]: any;
|
|
55
|
+
};
|
|
56
|
+
private static isPlainObject;
|
|
57
|
+
/**
|
|
58
|
+
* Rimuove ricorsivamente gli `undefined` annidati (Firestore non li supporta).
|
|
59
|
+
* NON trasforma null in deleteField: quello lo fai a top-level.
|
|
60
|
+
*/
|
|
61
|
+
static stripUndefinedDeep(value: any): any;
|
|
62
|
+
static cleanData(data: any): {
|
|
63
|
+
[k: string]: any;
|
|
64
|
+
};
|
|
65
|
+
onGetBeforeStoreSet<U extends FirestoreModel<T>>(instance: U): Promise<U>;
|
|
66
|
+
save({ offlineAllow, touchUpdate, localSet }?: OptionFireModel): Promise<void>;
|
|
67
|
+
update(data: Partial<Omit<T, 'id'>>, { offlineAllow, touchUpdate, localSet }?: OptionFireModel): Promise<void>;
|
|
68
|
+
delete(store: FirestoreStore_delete, opts?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
|
|
69
|
+
deleteJustOnline_NotLocalStore({ offlineAllow, localSet }?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
|
|
70
|
+
get isDeleted(): boolean;
|
|
71
|
+
timestampbleProps(): Timestampble;
|
|
72
|
+
touchUpdated(): Timestamp;
|
|
73
|
+
softDelete(optionFireModel?: OptionFireModel): Promise<void>;
|
|
74
|
+
/** 🔄 Ripristina dal cestino (se supportato) */
|
|
75
|
+
restore(optionFireModel?: OptionFireModel): Promise<void>;
|
|
76
|
+
/** Ritorna true se il model espone una chiave valido per il salvataggio su LocalStorage */
|
|
77
|
+
canLocalSave(localSet?: boolean): boolean;
|
|
78
|
+
/** Salva/aggiorna questo documento nel LocalStorage, sotto l’oggetto indicizzato per id */
|
|
79
|
+
localSet(_delete?: boolean): void;
|
|
80
|
+
}
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type QueryConstraint, type FieldPath, type OrderByDirection, type DocumentChange, type DocumentData } from 'firebase/firestore';
|
|
2
|
+
import { FirestoreModel } from './FirestoreModel';
|
|
3
|
+
import { type OptionFireModel } from './FirestoreModel';
|
|
4
|
+
import type { Reactive } from 'vue';
|
|
5
|
+
export interface GetProps {
|
|
6
|
+
ids?: string[];
|
|
7
|
+
lastByCreate?: number;
|
|
8
|
+
lastByUpdate?: number;
|
|
9
|
+
query?: QueryConstraint | QueryConstraint[];
|
|
10
|
+
limit?: number;
|
|
11
|
+
orderBy?: {
|
|
12
|
+
fieldPath: string | FieldPath;
|
|
13
|
+
directionStr?: OrderByDirection;
|
|
14
|
+
};
|
|
15
|
+
forceLocalSet?: boolean;
|
|
16
|
+
localSet?: boolean;
|
|
17
|
+
}
|
|
18
|
+
type Ctor<M, D> = {
|
|
19
|
+
new (data: D): M;
|
|
20
|
+
collectionName?: string;
|
|
21
|
+
};
|
|
22
|
+
export type FirestoreStoreReactive<M extends FirestoreModel<D>, D extends {
|
|
23
|
+
id: string;
|
|
24
|
+
}> = Reactive<FirestoreStore<M, D>>;
|
|
25
|
+
export type AnyFirestoreStoreReactive = FirestoreStoreReactive<FirestoreModel<{
|
|
26
|
+
id: string;
|
|
27
|
+
}>, {
|
|
28
|
+
id: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare class FirestoreStore<M extends FirestoreModel<D>, D extends {
|
|
31
|
+
id: string;
|
|
32
|
+
}> {
|
|
33
|
+
protected readonly ModelInstnce: Ctor<M, D>;
|
|
34
|
+
protected makeModel(id: string, data: Omit<D, 'id'>): M;
|
|
35
|
+
/** Se presente, verrà usata al posto di ModelInstnce.collectionName */
|
|
36
|
+
protected readonly _collectionPath?: string;
|
|
37
|
+
private debugLog;
|
|
38
|
+
items: Record<string, M>;
|
|
39
|
+
snapshotFnStop: (() => void) | null;
|
|
40
|
+
isFirstRun: boolean;
|
|
41
|
+
prevStartQuery: string | null;
|
|
42
|
+
get live(): boolean;
|
|
43
|
+
get ref(): import("@firebase/firestore").CollectionReference<DocumentData, DocumentData>;
|
|
44
|
+
constructor(ModelInstnce: Ctor<M, D>, opts?: {
|
|
45
|
+
collectionPath?: string;
|
|
46
|
+
});
|
|
47
|
+
/** Path effettiva della collezione di questo store */
|
|
48
|
+
protected get collectionPath(): string;
|
|
49
|
+
get name(): string;
|
|
50
|
+
get itemsActive(): Record<string, M>;
|
|
51
|
+
get itemsDeleted(): Record<string, M>;
|
|
52
|
+
get itemsArray(): M[];
|
|
53
|
+
/** 🔎 Solo elementi NON cancellati (m.deleteAt === null) */
|
|
54
|
+
get itemsActiveArray(): M[];
|
|
55
|
+
/** 🧺 Solo elementi cancellati (cestino) */
|
|
56
|
+
get itemsDeletedArray(): M[];
|
|
57
|
+
get isEmpty(): boolean;
|
|
58
|
+
/** 🔎 Versione array: NON cancellati */
|
|
59
|
+
get isActiveEmpty(): boolean;
|
|
60
|
+
/** 🧺 Versione array: cancellati */
|
|
61
|
+
get isDeletedEmpty(): boolean;
|
|
62
|
+
get localStorageKey(): any;
|
|
63
|
+
/**
|
|
64
|
+
* 📅 Restituisce un array ordinato per timestamp scelto.
|
|
65
|
+
* @param option 'createdAt' | 'updatedAt' | 'deleteAt'
|
|
66
|
+
* @returns Array ordinato in ordine discendente (più recente prima)
|
|
67
|
+
*/
|
|
68
|
+
itemsArrayOrderedBy(option: 'createdAt' | 'updatedAt' | 'deleteAt', deleted?: boolean): M[];
|
|
69
|
+
findItemsById(id: string | false | null | undefined): M;
|
|
70
|
+
get(opts?: GetProps): Promise<Record<string, M>>;
|
|
71
|
+
/**
|
|
72
|
+
* Legge doc per ids usando `documentId() in (...)`
|
|
73
|
+
* Firestore: max 10 elementi per `in` ma gestito fa chiamate a grruppi da 10
|
|
74
|
+
*/
|
|
75
|
+
getIds(ids: string[]): Promise<{
|
|
76
|
+
foundIds: string[] | false;
|
|
77
|
+
notFoundIds: string[] | false;
|
|
78
|
+
}>;
|
|
79
|
+
localGet(): void;
|
|
80
|
+
/**
|
|
81
|
+
* 🔴 Avvia il listening realtime (onSnapshot) sulla collection gestita dallo store.
|
|
82
|
+
*
|
|
83
|
+
* Questo metodo mette lo store in modalità "live", mantenendo sincronizzati
|
|
84
|
+
* gli `items` locali con Firestore in tempo reale.
|
|
85
|
+
*
|
|
86
|
+
* ⚠️ Non modifica la logica esistente di `get()`:
|
|
87
|
+
* - `start()` serve solo per l'ascolto realtime
|
|
88
|
+
* - `get()` resta una fetch one-shot
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
start(opts?: GetProps): Promise<void>;
|
|
92
|
+
onStartFirstRun(snapDocs: DocumentChange<DocumentData, DocumentData>[], forceLocalSet?: boolean): void;
|
|
93
|
+
stop(): void;
|
|
94
|
+
add(data: Omit<D, 'id'>, options?: Omit<OptionFireModel, 'touchUpdate'>): Promise<M>;
|
|
95
|
+
add(data: Omit<D, 'id'> & {
|
|
96
|
+
id?: string;
|
|
97
|
+
}, options?: Omit<OptionFireModel, 'touchUpdate'>): Promise<M>;
|
|
98
|
+
delete(id: string, opts?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
|
|
99
|
+
findByUid(uid: string): M;
|
|
100
|
+
/**
|
|
101
|
+
* Legge un singolo documento da Firestore e aggiorna items[id].
|
|
102
|
+
* Ritorna l'istanza oppure undefined se non esiste.
|
|
103
|
+
*/
|
|
104
|
+
getOne(id: string, options?: OptionFireModel): Promise<M | undefined>;
|
|
105
|
+
/**
|
|
106
|
+
* Ritorna l'istanza se già presente nello store, altrimenti la carica da Firestore.
|
|
107
|
+
*/
|
|
108
|
+
ensureOne(id: string): Promise<M | undefined>;
|
|
109
|
+
/** 🧹 Svuota completamente il LocalStorage associato al Model gestito dallo store */
|
|
110
|
+
localClear(): void;
|
|
111
|
+
}
|
|
112
|
+
export declare function validateQueryGetOpts(opts: GetProps & {
|
|
113
|
+
ids?: string[];
|
|
114
|
+
}): boolean;
|
|
115
|
+
export declare function buildConstraintsFromGetProps(opts: GetProps, alredyCheck?: boolean): QueryConstraint[] | false;
|
|
116
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type FirebaseApp } from "firebase/app";
|
|
2
|
+
import { getAnalytics } from "firebase/analytics";
|
|
3
|
+
import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
|
|
4
|
+
import { getFirestore } from 'firebase/firestore';
|
|
5
|
+
import { getStorage } from "firebase/storage";
|
|
6
|
+
import { getFunctions } from "firebase/functions";
|
|
7
|
+
import { getMessaging } from "firebase/messaging";
|
|
8
|
+
export interface FirebaseConfig {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
authDomain: string;
|
|
11
|
+
projectId: string;
|
|
12
|
+
storageBucket: string;
|
|
13
|
+
messagingSenderId: string;
|
|
14
|
+
appId: string;
|
|
15
|
+
measurementId?: string;
|
|
16
|
+
databaseURL?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare let auth: ReturnType<typeof getAuth>;
|
|
19
|
+
export declare let provider: GoogleAuthProvider;
|
|
20
|
+
export declare let analytics: ReturnType<typeof getAnalytics>;
|
|
21
|
+
export declare let db: ReturnType<typeof getFirestore>;
|
|
22
|
+
export declare let storage: ReturnType<typeof getStorage>;
|
|
23
|
+
export declare let functions: ReturnType<typeof getFunctions>;
|
|
24
|
+
export declare let messaging: ReturnType<typeof getMessaging>;
|
|
25
|
+
export declare function setupFirebase(firebaseConfig: FirebaseConfig): FirebaseApp;
|
|
26
|
+
export declare function ensureFirebase(): void;
|
|
27
|
+
export { signInWithPopup };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function middlewareCatchCall(error: any, showToast?: boolean): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AnyFirestoreStoreReactive, GetProps } from './FirestoreStore';
|
|
2
|
+
type StoreWatchItem = {
|
|
3
|
+
store: AnyFirestoreStoreReactive;
|
|
4
|
+
getOpts?: GetProps;
|
|
5
|
+
getAuthOpts?: GetProps;
|
|
6
|
+
checkLogin?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function useStoreWatch(stores: readonly StoreWatchItem[]): void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
2
|
+
export type RuleFn<V> = (value: V) => string | null;
|
|
3
|
+
export type Schema<T> = {
|
|
4
|
+
[K in keyof T]?: RuleFn<T[K]>[];
|
|
5
|
+
};
|
|
6
|
+
type ErrorsOf<T> = {
|
|
7
|
+
[K in keyof T]: string | null;
|
|
8
|
+
};
|
|
9
|
+
type TouchedOf<T> = {
|
|
10
|
+
[K in keyof T]: boolean;
|
|
11
|
+
};
|
|
12
|
+
export interface FormValidatorOptions<T extends Record<string, any>> {
|
|
13
|
+
id?: string;
|
|
14
|
+
initialValues: T;
|
|
15
|
+
validator?: Schema<T>;
|
|
16
|
+
onSubmit?: (values: Readonly<T>, touchedValues: Partial<T>, touched: Readonly<TouchedOf<T>>) => void | Promise<void>;
|
|
17
|
+
onInvalid?: (errors: Readonly<ErrorsOf<T>>) => void;
|
|
18
|
+
/** Validazione on change (default: true per tutti) */
|
|
19
|
+
validateOnChange?: boolean | Partial<Record<keyof T, boolean>>;
|
|
20
|
+
/** Validazione on change (default: true per tutti) */
|
|
21
|
+
touchOnChange?: boolean | Partial<Record<keyof T, boolean>>;
|
|
22
|
+
syncWith?: Ref<Partial<T> | null | undefined> | (() => Partial<T> | null | undefined);
|
|
23
|
+
submitOnChange?: boolean | number;
|
|
24
|
+
syncPreference?: 'local' | 'db';
|
|
25
|
+
effects?: Partial<Record<keyof T, (value: T[keyof T], fv: FormValidator<T>) => void>>;
|
|
26
|
+
onAnyChange?: (key: keyof T, value: T[keyof T], fv: FormValidator<T>) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare class FormValidator<T extends Record<string, any>> {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly values: T;
|
|
31
|
+
readonly errors: ErrorsOf<T>;
|
|
32
|
+
readonly touched: TouchedOf<T>;
|
|
33
|
+
private _initial;
|
|
34
|
+
private readonly schema;
|
|
35
|
+
private readonly _onSubmit?;
|
|
36
|
+
private readonly _onInvalid?;
|
|
37
|
+
private readonly _validateOnChangeMap;
|
|
38
|
+
private readonly _touchOnChangeMap;
|
|
39
|
+
private readonly _stopWatch?;
|
|
40
|
+
private _fieldCache;
|
|
41
|
+
private _allFields?;
|
|
42
|
+
private _submitOnChange?;
|
|
43
|
+
private _suspendAutoSubmit;
|
|
44
|
+
private _debouncedSubmit?;
|
|
45
|
+
private _syncPreference;
|
|
46
|
+
private readonly _effects?;
|
|
47
|
+
private readonly _onAnyChange?;
|
|
48
|
+
private _makeDebouncedSubmit;
|
|
49
|
+
constructor(options: FormValidatorOptions<T>);
|
|
50
|
+
constructor(initial: T, schema?: Schema<T>);
|
|
51
|
+
touch<K extends keyof T>(key: K): void;
|
|
52
|
+
touchAll(): void;
|
|
53
|
+
field<K extends keyof T>(key: K): ComputedRef<T[K]>;
|
|
54
|
+
fields(): {
|
|
55
|
+
[K in keyof T]: ComputedRef<T[K]>;
|
|
56
|
+
};
|
|
57
|
+
set<K extends keyof T>(key: K, value: T[K], validateNow?: boolean): void;
|
|
58
|
+
validateField<K extends keyof T>(key: K): boolean;
|
|
59
|
+
validateAll(): boolean;
|
|
60
|
+
fill(model: Partial<T>, options?: {
|
|
61
|
+
validate: boolean;
|
|
62
|
+
}): void;
|
|
63
|
+
reset({ keepTouched }?: {
|
|
64
|
+
keepTouched?: boolean;
|
|
65
|
+
}): void;
|
|
66
|
+
resetWithInitialValues(initialValues: T): void;
|
|
67
|
+
bindField<K extends keyof T>(key: K, forceValidateOnChange?: boolean): ComputedRef<T[K]>;
|
|
68
|
+
showError<K extends keyof T>(key: K): string | null;
|
|
69
|
+
hasError(k: keyof T): boolean;
|
|
70
|
+
getFieldId<K extends keyof T>(key: K): string;
|
|
71
|
+
getFieldIdError<K extends keyof T>(key: K): string;
|
|
72
|
+
getFieldProps<K extends keyof T>(key: K): {
|
|
73
|
+
id: string;
|
|
74
|
+
'aria-invalid': boolean;
|
|
75
|
+
'aria-describedby': string;
|
|
76
|
+
class: {
|
|
77
|
+
'is-invalid': boolean;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
get isValid(): boolean;
|
|
81
|
+
get isDirty(): boolean;
|
|
82
|
+
get touchedValues(): Partial<T>;
|
|
83
|
+
dispose(): void;
|
|
84
|
+
/** Handler pronto per il form: @submit.prevent="fv.submit" */
|
|
85
|
+
submit: () => Promise<void>;
|
|
86
|
+
setSyncPreference(pref: 'local' | 'db'): void;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Timestamp } from 'firebase/firestore';
|
|
2
|
+
/** Timestamp | Date → 'YYYY-MM-DD' (input type="date") */
|
|
3
|
+
export declare function timestampInputDate(v: Timestamp | Date | null | undefined): string;
|
|
4
|
+
/** Timestamp | Date → 'HH:mm' (input type="time") */
|
|
5
|
+
export declare function timestampInputTime(v: Timestamp | Date | null | undefined): string;
|
|
6
|
+
/** Timestamp | Date → 'YYYY-MM-DDTHH:mm' (input type="datetime-local") */
|
|
7
|
+
export declare function timestampInputDateTimeLocal(v: Timestamp | Date | null | undefined): string;
|
|
8
|
+
/** 'YYYY-MM-DD' → Date (locale) */
|
|
9
|
+
export declare function inputDateToDate(date: string): Date | null;
|
|
10
|
+
/** 'YYYY-MM-DD' + 'HH:mm' → Timestamp */
|
|
11
|
+
export declare function inputDateTimeToTimestamp(date: string, time?: string): Timestamp | null;
|
|
12
|
+
/** Qualsiasi valore → stringa sicura per input text */
|
|
13
|
+
export declare function valueToInputString(v: unknown, fallback?: string): string;
|
|
14
|
+
/** Qualsiasi valore → number | '' (input type="number") */
|
|
15
|
+
export declare function valueToInputNumber(v: unknown): number | '';
|
|
16
|
+
/** Qualsiasi valore → boolean (input type="checkbox") */
|
|
17
|
+
export declare function valueToInputBoolean(v: unknown): boolean;
|
|
18
|
+
/** Garantisce sempre un array di stringhe (select multiple, tag, ecc.) */
|
|
19
|
+
export declare function valueToStringArray(v: unknown): string[];
|
|
20
|
+
/** Normalizza value per <select> (evita undefined) */
|
|
21
|
+
export declare function valueToSelect<T extends string>(v: unknown, allowed?: readonly T[]): T | '';
|
|
22
|
+
/** Timestamp | Date → locale string breve */
|
|
23
|
+
export declare function timestampToLocale(v: Timestamp | Date | null | undefined, locale?: any): string;
|
|
24
|
+
/** Stringa vuota → placeholder visivo */
|
|
25
|
+
export declare function emptyToDash(v: unknown): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RuleFn } from "./FormValidator";
|
|
2
|
+
export declare const required: (msg?: string) => RuleFn<any>;
|
|
3
|
+
export declare const email: (msg?: string) => RuleFn<string>;
|
|
4
|
+
export declare const dateISO: (msg?: string) => RuleFn<string>;
|
|
5
|
+
export declare const url: (msg?: string) => RuleFn<string>;
|
|
6
|
+
export declare const oneOf: <V extends string>(choices: readonly V[], msg?: string) => RuleFn<V | undefined>;
|
|
7
|
+
export declare const requiredTrue: (msg?: string) => RuleFn<boolean>;
|
|
8
|
+
/** Deve essere un numero valido */
|
|
9
|
+
export declare const isNumber: (msg?: string) => RuleFn<any>;
|
|
10
|
+
/** Numero minimo (incluso) */
|
|
11
|
+
export declare const minNumber: (min: number, msg?: string) => RuleFn<number | string>;
|
|
12
|
+
/** Numero massimo (incluso) */
|
|
13
|
+
export declare const maxNumber: (max: number, msg?: string) => RuleFn<number | string>;
|
|
14
|
+
/** Lunghezza minima stringa */
|
|
15
|
+
export declare const minLength: (min: number, msg?: string) => RuleFn<string>;
|
|
16
|
+
/** Lunghezza massima stringa */
|
|
17
|
+
export declare const maxLength: (max: number, msg?: string) => RuleFn<string>;
|
|
18
|
+
export declare const password: (msg?: string) => RuleFn<string>;
|
|
19
|
+
/** Password con lunghezza minima */
|
|
20
|
+
export declare const passwordWithMin: (min: number, msg?: string) => RuleFn<string>;
|
|
21
|
+
/** Conferma password: deve coincidere con la password originale */
|
|
22
|
+
export declare const passwordRetype: (getOriginal: () => string | null | undefined, msg?: string) => RuleFn<string>;
|
|
23
|
+
/** Deve essere dopo (>=) una data di riferimento */
|
|
24
|
+
export declare const dateAfter: (getMin: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
|
|
25
|
+
/** Deve essere prima (<=) di una data di riferimento */
|
|
26
|
+
export declare const dateBefore: (getMax: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
|
|
27
|
+
/** Deve essere compresa tra due date (inclusi) */
|
|
28
|
+
export declare const dateBetween: (getMin: () => string | Date | null | undefined, getMax: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Gender = '' | 'm' | 'f' | 'o';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const LS: {
|
|
2
|
+
defaultKey: {
|
|
3
|
+
isDev: string;
|
|
4
|
+
debugMod: string;
|
|
5
|
+
currentUser: string;
|
|
6
|
+
};
|
|
7
|
+
/** Lettura con gestione errori, valore */
|
|
8
|
+
getStr(key: string): string | undefined;
|
|
9
|
+
/** Lettura con gestione errori, valore */
|
|
10
|
+
getParsed(key: string): any;
|
|
11
|
+
/** Scrittura sicura con serializzazione JSON */
|
|
12
|
+
set(key: string, value: any): any;
|
|
13
|
+
/** Aggiorna un valore esistente */
|
|
14
|
+
update(key: string, data: any): any;
|
|
15
|
+
/** Aggiunge uno o più elementi a un array salvato in localStorage */
|
|
16
|
+
push(key: string, ...items: any[]): any;
|
|
17
|
+
/** Rimozione sicura */
|
|
18
|
+
remove(key: string): void;
|
|
19
|
+
/** Alias compatibile (ma corretto) */
|
|
20
|
+
delete(key: string): void;
|
|
21
|
+
/** Verifica se una chiave esiste */
|
|
22
|
+
has(key: string): boolean;
|
|
23
|
+
/** Elenca tutte le chiavi conosciute (solo quelle definite in LocalStorageKey) */
|
|
24
|
+
keys(): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Svuota il localStorage tranne le chiavi indicate
|
|
27
|
+
* @param exclude una chiave o un array di chiavi da preservare
|
|
28
|
+
*/
|
|
29
|
+
clear(exclude?: string | string[]): void;
|
|
30
|
+
/** Migra il valore da una chiave a un’altra */
|
|
31
|
+
migrate(oldKey: string, newKey: string): void;
|
|
32
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { User } from '../../models/User';
|
|
2
|
+
export type PushMsgContent = NotificationOptions & {
|
|
3
|
+
title: string;
|
|
4
|
+
};
|
|
5
|
+
export interface PushMsg {
|
|
6
|
+
reg: ServiceWorkerRegistration | undefined;
|
|
7
|
+
VAPID_PUBLIC_KEY: string | undefined;
|
|
8
|
+
isNotificationSupported: boolean;
|
|
9
|
+
permission: NotificationPermission;
|
|
10
|
+
needToAskPermission: boolean;
|
|
11
|
+
askPermission(currentUser: User): Promise<NotificationPermission>;
|
|
12
|
+
send(currentUser: User, content: string | PushMsgContent): Promise<void>;
|
|
13
|
+
sendTo(uid: string, content: string | PushMsgContent): Promise<boolean>;
|
|
14
|
+
getCurrentFcmToken(): Promise<string | null>;
|
|
15
|
+
registerFcmToken(currentUser: User): Promise<string | null>;
|
|
16
|
+
removeThisDeviceToken(currentUser: User): Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
export declare const pushMsg: PushMsg;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Timestamp } from "firebase/firestore";
|
|
2
|
+
export declare function reviveTimestamp(json: {
|
|
3
|
+
seconds: number;
|
|
4
|
+
nanoseconds: number;
|
|
5
|
+
type?: string;
|
|
6
|
+
} | Timestamp): Timestamp;
|
|
7
|
+
export declare function reviveTimestampsDeep(value: any): any;
|
|
8
|
+
export declare const serializeTimestamp: (value: any) => any;
|