@edgedev/firebase 1.0.25 → 1.0.28

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.
Files changed (2) hide show
  1. package/index.ts +237 -57
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { initializeApp } from "firebase/app";
2
- import { reactive, ref } from "vue";
2
+ import { reactive } from "vue";
3
3
 
4
4
  import {
5
5
  getFirestore,
@@ -12,10 +12,63 @@ import {
12
12
  WhereFilterOp,
13
13
  QueryConstraint,
14
14
  Unsubscribe,
15
- where
15
+ where,
16
+ deleteDoc,
17
+ getDocs,
18
+ getDoc,
19
+ orderBy,
20
+ limit,
21
+ Query,
22
+ startAt,
23
+ startAfter
16
24
  } from "firebase/firestore";
17
25
 
18
- import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
26
+ import {
27
+ getAuth,
28
+ setPersistence,
29
+ browserSessionPersistence,
30
+ browserLocalPersistence,
31
+ Persistence,
32
+ signInWithEmailAndPassword,
33
+ onAuthStateChanged,
34
+ signOut
35
+ } from "firebase/auth";
36
+
37
+ interface FirestoreQuery {
38
+ field: string;
39
+ operator: WhereFilterOp; // '==' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'array-contains-any';
40
+ value: unknown;
41
+ }
42
+
43
+ interface FirestoreOrderBy {
44
+ field: string;
45
+ direction: "asc" | "desc";
46
+ }
47
+
48
+ interface FirestoreLimit {
49
+ limit: number;
50
+ }
51
+
52
+ interface CollectionUnsubscribeObject {
53
+ [key: string]: Unsubscribe;
54
+ }
55
+
56
+ interface CollectionDataObject {
57
+ [key: string]: object;
58
+ }
59
+
60
+ interface UserDataObject {
61
+ uid: string | null;
62
+ email: string;
63
+ loggedIn: boolean;
64
+ logInError: boolean;
65
+ logInErrorMessage: string;
66
+ }
67
+
68
+ interface Credentials {
69
+ email: string;
70
+ password: string;
71
+ }
19
72
 
20
73
  const firebaseConfig = {
21
74
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY as string,
@@ -28,38 +81,133 @@ const firebaseConfig = {
28
81
  };
29
82
 
30
83
  // Initialize Firebase
31
- const app = initializeApp(firebaseConfig);
32
- const auth = getAuth(app);
33
- console.log(auth);
34
- const db = getFirestore(app);
35
-
36
- // export const signIn = async (credentials: Credentials): Promise<object> => {
37
- // const user = await signInWithEmailAndPassword(
38
- // auth,
39
- // credentials.email,
40
- // credentials.password
41
- // );
42
- // console.log(user);
43
- // return user;
44
- // };
84
+ export const app = initializeApp(firebaseConfig);
85
+ export const auth = getAuth(app);
86
+ export const db = getFirestore(app);
87
+
88
+ onAuthStateChanged(auth, (userAuth) => {
89
+ if (userAuth) {
90
+ user.email = userAuth.email;
91
+ user.uid = userAuth.uid;
92
+ user.loggedIn = true;
93
+ user.logInError = false;
94
+ user.logInErrorMessage = "";
95
+ } else {
96
+ user.email = "";
97
+ user.uid = null;
98
+ user.loggedIn = false;
99
+ user.logInError = false;
100
+ user.logInErrorMessage = "";
101
+ }
102
+ });
103
+
104
+ // Composable to logout
105
+ export const logOut = (): void => {
106
+ signOut(auth)
107
+ .then(() => {
108
+ Object.keys(unsubscibe).forEach((key) => {
109
+ if (unsubscibe[key] instanceof Function) {
110
+ unsubscibe[key]();
111
+ unsubscibe[key] = null;
112
+ }
113
+ });
114
+ })
115
+ .catch(() => {
116
+ // Do nothing
117
+ });
118
+ };
119
+
120
+ // Composable to login and set persistence
121
+ export const logIn = (credentials: Credentials, isPersistant = false): void => {
122
+ logOut();
123
+ let persistence: Persistence = browserSessionPersistence;
124
+ if (isPersistant) {
125
+ persistence = browserLocalPersistence;
126
+ }
127
+ setPersistence(auth, persistence)
128
+ .then(() => {
129
+ signInWithEmailAndPassword(auth, credentials.email, credentials.password)
130
+ .then(() => {
131
+ // do nothing
132
+ })
133
+ .catch((error) => {
134
+ user.email = "";
135
+ user.uid = null;
136
+
137
+ user.loggedIn = false;
138
+ user.logInError = true;
139
+ user.logInErrorMessage = error.code + ": " + error.message;
140
+ });
141
+ })
142
+ .catch((error) => {
143
+ user.email = "";
144
+ user.uid = null;
145
+
146
+ user.loggedIn = false;
147
+ user.logInError = true;
148
+ user.logInErrorMessage = error.code + ": " + error.message;
149
+ });
150
+ };
151
+
152
+ // Keeping this for reference on how to Type a Ref.
153
+ // export const user = ref<UserDataObject>({
154
+ // uid: null,
155
+ // email: "",
156
+ // loggedIn: false,
157
+ // logInError: false,
158
+ // logInErrorMessage: ""
159
+ // });
45
160
 
46
161
  // Simple Store Items (add matching key per firebase collection)
47
162
  export const data: CollectionDataObject = reactive({});
48
163
  export const unsubscibe: CollectionUnsubscribeObject = reactive({});
49
- export const user = ref<UserDataObject>({ uid: "", email: "" });
164
+ export const user: UserDataObject = reactive({
165
+ uid: null,
166
+ email: "",
167
+ loggedIn: false,
168
+ logInError: false,
169
+ logInErrorMessage: ""
170
+ });
171
+
172
+ export const getDocData = async (
173
+ collectionPath: string,
174
+ docId: string
175
+ ): Promise<{ [key: string]: unknown }> => {
176
+ const docRef = doc(db, collectionPath, docId);
177
+ const docSnap = await getDoc(docRef);
178
+ const docData = docSnap.data();
179
+ docData.docId = docSnap.id;
180
+ return docData;
181
+ };
182
+
183
+ export const getStaticData = async (
184
+ collectionPath: string,
185
+ queryList: FirestoreQuery[] = [],
186
+ orderList: FirestoreOrderBy[] = [],
187
+ max: 0,
188
+ after = ""
189
+ ): Promise<{ [key: string]: unknown }> => {
190
+ const data: { [key: string]: unknown } = {};
191
+ const q = getQuery(collectionPath, queryList, orderList, max, after);
192
+ const docs = await getDocs(q);
193
+ docs.forEach((doc) => {
194
+ const item = doc.data();
195
+ item.docId = doc.id;
196
+ data[doc.id] = item;
197
+ });
198
+ return data;
199
+ };
50
200
 
51
201
  // Composable to start snapshot listener and set unsubscribe function
52
202
  export const startSnapshot = (
53
203
  collectionPath: string,
54
- queryList: FirestoreQuery[] = []
204
+ queryList: FirestoreQuery[] = [],
205
+ orderList: FirestoreOrderBy[] = [],
206
+ max = 0,
207
+ after = ""
55
208
  ): void => {
56
- if (data[collectionPath] instanceof Function) {
57
- stopSnapshot(collectionPath);
58
- }
59
- const queryConditions: QueryConstraint[] = queryList.map((condition) =>
60
- where(condition.field, condition.operator, condition.value)
61
- );
62
- const q = query(collection(db, collectionPath), ...queryConditions);
209
+ data[collectionPath] = {};
210
+ const q = getQuery(collectionPath, queryList, orderList, max, after);
63
211
  const unsubscribe = onSnapshot(q, (querySnapshot) => {
64
212
  const items = {};
65
213
  querySnapshot.forEach((doc) => {
@@ -72,28 +220,83 @@ export const startSnapshot = (
72
220
  unsubscibe[collectionPath] = unsubscribe;
73
221
  };
74
222
 
75
- export const storeDoc = (collectionPath: string, item: object): void => {
223
+ const getQuery = (
224
+ collectionPath: string,
225
+ queryList: FirestoreQuery[] = [],
226
+ orderList: FirestoreOrderBy[] = [],
227
+ max = 0,
228
+ after = ""
229
+ ): Query => {
230
+ const queryConditions: QueryConstraint[] = queryList.map((condition) =>
231
+ where(condition.field, condition.operator, condition.value)
232
+ );
233
+
234
+ const orderConditions: QueryConstraint[] = orderList.map((condition) =>
235
+ orderBy(condition.field, condition.direction)
236
+ );
237
+
238
+ let limitList: FirestoreLimit[] = [];
239
+ if (max > 0) {
240
+ limitList = [{ limit: max }];
241
+ }
242
+
243
+ const limitConditions: QueryConstraint[] = limitList.map((condition) =>
244
+ limit(condition.limit)
245
+ );
246
+ if (after) {
247
+ return query(
248
+ collection(db, collectionPath),
249
+ ...queryConditions,
250
+ ...orderConditions,
251
+ ...limitConditions,
252
+ startAfter(after)
253
+ );
254
+ }
255
+ return query(
256
+ collection(db, collectionPath),
257
+ ...queryConditions,
258
+ ...orderConditions,
259
+ ...limitConditions
260
+ );
261
+ };
262
+
263
+ // Composable to update/add a document
264
+ export const storeDoc = async (
265
+ collectionPath: string,
266
+ item: object
267
+ ): Promise<void> => {
76
268
  const cloneItem = JSON.parse(JSON.stringify(item));
77
- const current_time = new Date().getTime();
78
- cloneItem.last_updated = current_time;
79
- cloneItem.uid = user["uid"];
269
+ const currentTime = new Date().getTime();
270
+ cloneItem.last_updated = currentTime;
271
+ cloneItem.uid = user.uid;
80
272
  if (!Object.prototype.hasOwnProperty.call(cloneItem, "doc_created_at")) {
81
- cloneItem.doc_created_at = current_time;
273
+ cloneItem.doc_created_at = currentTime;
82
274
  }
83
275
  if (Object.prototype.hasOwnProperty.call(cloneItem, "docId")) {
84
276
  const docId = cloneItem.docId;
85
277
  if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
86
278
  data[collectionPath][docId] = cloneItem;
87
279
  }
88
- delete cloneItem.docId;
89
280
  const docRef = doc(db, collectionPath, docId);
90
281
  updateDoc(docRef, cloneItem);
91
282
  } else {
283
+ const docRef = await addDoc(collection(db, collectionPath), cloneItem);
92
284
  if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
93
- data[collectionPath][current_time] = cloneItem;
285
+ data[collectionPath][docRef.id] = cloneItem;
286
+ }
287
+ storeDoc(collectionPath, { ...cloneItem, docId: docRef.id });
288
+ }
289
+ };
290
+
291
+ // Composable to delete a document
292
+ export const removeDoc = (collectionPath: string, docId: string): void => {
293
+ // Just in case getting collection back from firebase is slow:
294
+ if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
295
+ if (Object.prototype.hasOwnProperty.call(data[collectionPath], docId)) {
296
+ delete data[collectionPath][docId];
94
297
  }
95
- addDoc(collection(db, collectionPath), cloneItem);
96
298
  }
299
+ deleteDoc(doc(db, collectionPath, docId));
97
300
  };
98
301
 
99
302
  // Composable to stop snapshot listener
@@ -103,26 +306,3 @@ export const stopSnapshot = (collectionPath: string): void => {
103
306
  unsubscibe[collectionPath] = null;
104
307
  }
105
308
  };
106
-
107
- interface Credentials {
108
- email: string;
109
- password: string;
110
- }
111
- interface FirestoreQuery {
112
- field: string;
113
- operator: WhereFilterOp; // '==' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'array-contains-any';
114
- value: unknown;
115
- }
116
-
117
- interface CollectionUnsubscribeObject {
118
- [key: string]: Unsubscribe;
119
- }
120
-
121
- interface CollectionDataObject {
122
- [key: string]: object;
123
- }
124
-
125
- interface UserDataObject {
126
- uid: string | null;
127
- email: string;
128
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "1.0.25",
3
+ "version": "1.0.28",
4
4
  "description": "Composables and stores for firebase",
5
5
  "main": "index.ts",
6
6
  "author": "Seth Fischer",