update
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
import useDebounce from './useDebounce';
|
||||
|
||||
export {useDebounce};
|
||||
@@ -0,0 +1,51 @@
|
||||
import { useEffect, useState } from "reactn";
|
||||
|
||||
import algoliasearch from "algoliasearch/lite";
|
||||
|
||||
export default ({
|
||||
query = "",
|
||||
options = {},
|
||||
algoliaObject: { index = null, projectID, publicKey },
|
||||
documentID = "id",
|
||||
}) => {
|
||||
const [result, setResult] = useState([]);
|
||||
const [indexAlgolia, setIndexAlgolia] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!indexAlgolia) {
|
||||
setIndexAlgolia(algoliasearch(projectID, publicKey).initIndex(index));
|
||||
}
|
||||
|
||||
return () => {
|
||||
setIndexAlgolia(null);
|
||||
};
|
||||
}, [index]);
|
||||
|
||||
useEffect(() => {
|
||||
if (indexAlgolia) {
|
||||
getSearchResult();
|
||||
}
|
||||
}, [query, indexAlgolia]);
|
||||
|
||||
const getSearchResult = async () => {
|
||||
try {
|
||||
if (query.length > 1) {
|
||||
const { hits } = await indexAlgolia.search(query, options);
|
||||
|
||||
setResult(
|
||||
hits.map((itemHit) => ({
|
||||
...itemHit,
|
||||
[documentID]: itemHit.objectID,
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
setResult([]);
|
||||
}
|
||||
} catch (e) {
|
||||
setResult([]);
|
||||
console.log("ALGOLIA" + e);
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
|
||||
const useAsyncStorage = (key, initialValue) => {
|
||||
const [data, setData] = useState(initialValue);
|
||||
const [retrievedFromStorage, setRetrievedFromStorage] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const value = await AsyncStorage.getItem(key);
|
||||
console.log(`Retrieved data for ${key}: ${value}`);
|
||||
setData(JSON.parse(value) || initialValue);
|
||||
setRetrievedFromStorage(true);
|
||||
} catch (error) {
|
||||
console.error("useAsyncStorage getItem error:", error);
|
||||
}
|
||||
})();
|
||||
}, [key, initialValue]);
|
||||
|
||||
const setNewData = async (value) => {
|
||||
try {
|
||||
await AsyncStorage.setItem(key, JSON.stringify(value));
|
||||
setData(value);
|
||||
} catch (error) {
|
||||
console.error("useAsyncStorage setItem error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return [data, setNewData, retrievedFromStorage];
|
||||
};
|
||||
export default useAsyncStorage;
|
||||
@@ -0,0 +1,167 @@
|
||||
import { useState, setGlobal } from "reactn";
|
||||
import { useEffect } from "react";
|
||||
import _ from "lodash";
|
||||
|
||||
export default function useDataFromRef({
|
||||
ref,
|
||||
|
||||
initialState = [],
|
||||
refreshArray = [],
|
||||
|
||||
initialDocumentRef = null,
|
||||
documentID = "id",
|
||||
listener = false,
|
||||
|
||||
condition = true,
|
||||
simpleRef = false,
|
||||
|
||||
usePagination = false,
|
||||
|
||||
updateGlobalState = null,
|
||||
|
||||
batchSize = 4,
|
||||
|
||||
format = null,
|
||||
onUpdate = () => null,
|
||||
}) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [endReached, setEndReached] = useState(false);
|
||||
const [data, setData] = useState(initialState);
|
||||
const [lastVisible, setLastVisible] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (condition) {
|
||||
if (listener && !usePagination) {
|
||||
const subData = getListenerData();
|
||||
return () => subData?.();
|
||||
} else {
|
||||
resetState();
|
||||
|
||||
getData({ paginate: usePagination });
|
||||
}
|
||||
} else {
|
||||
resetState();
|
||||
}
|
||||
}, [...refreshArray, condition, usePagination]);
|
||||
|
||||
const loadMore = () => {
|
||||
if (!loading && !endReached) {
|
||||
getData({ paginate: true });
|
||||
console.log("Loading more");
|
||||
}
|
||||
};
|
||||
|
||||
const resetState = () => {
|
||||
if (!_.isEqual(data, initialState)) {
|
||||
onUpdate(initialState);
|
||||
}
|
||||
|
||||
console.log("Reset state", initialState);
|
||||
|
||||
setEndReached(false);
|
||||
setLastVisible(null);
|
||||
setData(initialState);
|
||||
};
|
||||
|
||||
const getData = async ({ paginate = false } = {}) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
let newData = simpleRef ? null : [];
|
||||
let initialDoc = null;
|
||||
|
||||
if (initialDocumentRef && !lastVisible && !simpleRef) {
|
||||
initialDoc = await initialDocumentRef.get();
|
||||
}
|
||||
|
||||
const dynamicRef =
|
||||
paginate && lastVisible
|
||||
? ref.startAfter(lastVisible).limit(batchSize)
|
||||
: initialDoc
|
||||
? ref.startAt(initialDoc).limit(batchSize)
|
||||
: paginate
|
||||
? ref.limit(batchSize)
|
||||
: ref;
|
||||
|
||||
const dataSnap = await dynamicRef.get();
|
||||
|
||||
if (simpleRef && dataSnap.data()) {
|
||||
newData = { ...dataSnap.data(), [documentID]: dataSnap.id };
|
||||
} else if (!simpleRef && dataSnap.docs.length > 0) {
|
||||
newData = dataSnap.docs.map((item) => {
|
||||
return { ...item.data(), [documentID]: item.id };
|
||||
});
|
||||
|
||||
if (paginate) {
|
||||
if (batchSize !== dataSnap.docs.length) {
|
||||
setEndReached(true);
|
||||
}
|
||||
setLastVisible(dataSnap.docs[dataSnap.docs.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (newData) {
|
||||
if (paginate) {
|
||||
console.log("new pagination");
|
||||
await updateData([...data, ...newData]);
|
||||
} else {
|
||||
await updateData(newData);
|
||||
}
|
||||
} else {
|
||||
console.log("NO DATA");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === "firestore/permission-denied") {
|
||||
console.warn(
|
||||
"Permission denied for ref: ",
|
||||
ref?._collectionPath?.relativeName
|
||||
);
|
||||
} else {
|
||||
console.log(e);
|
||||
}
|
||||
await updateData([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getListenerData = () => {
|
||||
return ref?.onSnapshot(
|
||||
async (dataSnap) => {
|
||||
let newData;
|
||||
|
||||
if (simpleRef) {
|
||||
newData = { ...dataSnap.data(), [documentID]: dataSnap.id };
|
||||
} else {
|
||||
newData = dataSnap.docs.map((item) => {
|
||||
return { ...item.data(), [documentID]: item.id };
|
||||
});
|
||||
}
|
||||
await updateData(newData);
|
||||
setLoading(false);
|
||||
},
|
||||
async (e) => {
|
||||
if (e.code === "firestore/permission-denied") {
|
||||
console.warn(
|
||||
"Permission denied for ref: ",
|
||||
ref?._collectionPath?.relativeName
|
||||
);
|
||||
} else {
|
||||
console.log(e);
|
||||
}
|
||||
await updateData([]);
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const updateData = async (newData) => {
|
||||
setData(format ? await format(newData) : newData);
|
||||
onUpdate(newData);
|
||||
|
||||
if (updateGlobalState) {
|
||||
setGlobal({ [updateGlobalState]: data });
|
||||
}
|
||||
};
|
||||
|
||||
return { data, setData, loading, loadMore };
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export const useFirestorePagination = ({
|
||||
ref = null,
|
||||
refreshArray = [],
|
||||
condition = false,
|
||||
documentID = "id",
|
||||
batchSize = 10,
|
||||
maxLoads = 15, // Maximum number of times loadMore can be called
|
||||
}) => {
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [lastVisible, setLastVisible] = useState(null);
|
||||
const [error, setError] = useState(null);
|
||||
const [loadMoreCount, setLoadMoreCount] = useState(0); // Counter for loadMore invocations
|
||||
|
||||
useEffect(() => {
|
||||
let unsubscribe = () => {};
|
||||
|
||||
if (condition && ref) {
|
||||
setLoading(true);
|
||||
unsubscribe = ref.limit(batchSize).onSnapshot(
|
||||
(snapshot) => {
|
||||
const fetchedDocuments = snapshot.docs.map((doc) => ({
|
||||
[documentID]: doc.id,
|
||||
...doc.data(),
|
||||
}));
|
||||
const lastVisibleDocument = snapshot.docs[snapshot.docs.length - 1];
|
||||
setData(fetchedDocuments);
|
||||
setLastVisible(lastVisibleDocument);
|
||||
setLoading(false);
|
||||
},
|
||||
(err) => {
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return () => unsubscribe();
|
||||
}, [...refreshArray, condition, ref, batchSize]);
|
||||
|
||||
const loadMore = () => {
|
||||
if (lastVisible && !loading && loadMoreCount < maxLoads) {
|
||||
setLoading(true);
|
||||
setLoadMoreCount((count) => count + 1); // Increment loadMore counter
|
||||
|
||||
ref
|
||||
.startAfter(lastVisible)
|
||||
.limit(batchSize)
|
||||
.onSnapshot(
|
||||
(snapshot) => {
|
||||
const newDocuments = snapshot.docs.map((doc) => ({
|
||||
[documentID]: doc.id,
|
||||
...doc.data(),
|
||||
}));
|
||||
setData((prev) => [...prev, ...newDocuments]);
|
||||
setLastVisible(snapshot.docs[snapshot.docs.length - 1]);
|
||||
setLoading(false);
|
||||
},
|
||||
(err) => {
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Function to check if more data can be loaded
|
||||
const canLoadMore = loadMoreCount < maxLoads;
|
||||
|
||||
return { data, loading, error, loadMore, canLoadMore };
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import { responsiveWidth } from "react-native-responsive-dimensions";
|
||||
|
||||
const getLayoutType = () => {
|
||||
const windowWidth = responsiveWidth(100);
|
||||
|
||||
const isWeb = Platform.OS === "web";
|
||||
const isNative = !isWeb;
|
||||
const isIOS = Platform.OS === "ios";
|
||||
|
||||
const isTauri = typeof window.__TAURI__ !== "undefined";
|
||||
|
||||
const superSmallDesktopBreakpoint = 800;
|
||||
const smallDesktopBreakpoint = 1100;
|
||||
const mediumDesktopBreakpoint = smallDesktopBreakpoint * 1.2;
|
||||
const largeDesktopBreakpoint = smallDesktopBreakpoint * 1.5;
|
||||
|
||||
const isDesktop = windowWidth > superSmallDesktopBreakpoint;
|
||||
|
||||
const isDesktopWeb = isDesktop && isWeb;
|
||||
const isMobile = !isDesktop;
|
||||
const isMobileWeb = isMobile && isWeb;
|
||||
const isMobileNative = isMobile && !isWeb;
|
||||
const isDesktopNative = isDesktop && !isWeb;
|
||||
|
||||
const isSuperSmallDesktop =
|
||||
windowWidth > superSmallDesktopBreakpoint &&
|
||||
windowWidth < smallDesktopBreakpoint;
|
||||
const isSmallDesktop =
|
||||
windowWidth > smallDesktopBreakpoint &&
|
||||
windowWidth < mediumDesktopBreakpoint;
|
||||
const isMediumDesktop = windowWidth > mediumDesktopBreakpoint;
|
||||
const isLargeDesktop = windowWidth > largeDesktopBreakpoint;
|
||||
|
||||
const sidebarWidth = windowWidth > 1350 ? 400 : 320;
|
||||
|
||||
return {
|
||||
isWeb,
|
||||
isNative,
|
||||
isIOS,
|
||||
isTauri,
|
||||
|
||||
superSmallDesktopBreakpoint,
|
||||
smallDesktopBreakpoint,
|
||||
mediumDesktopBreakpoint,
|
||||
largeDesktopBreakpoint,
|
||||
isDesktop,
|
||||
isSuperSmallDesktop,
|
||||
isSmallDesktop,
|
||||
isMediumDesktop,
|
||||
isLargeDesktop,
|
||||
isDesktopWeb,
|
||||
isMobile,
|
||||
isMobileWeb,
|
||||
isMobileNative,
|
||||
isDesktopNative,
|
||||
sidebarWidth,
|
||||
windowWidth,
|
||||
};
|
||||
};
|
||||
|
||||
export const {
|
||||
isWeb,
|
||||
isNative,
|
||||
isIOS,
|
||||
isTauri,
|
||||
|
||||
superSmallDesktopBreakpoint,
|
||||
smallDesktopBreakpoint,
|
||||
mediumDesktopBreakpoint,
|
||||
largeDesktopBreakpoint,
|
||||
isDesktop,
|
||||
isSuperSmallDesktop,
|
||||
isSmallDesktop,
|
||||
isMediumDesktop,
|
||||
isLargeDesktop,
|
||||
isDesktopWeb,
|
||||
isMobile,
|
||||
isMobileWeb,
|
||||
isMobileNative,
|
||||
sidebarWidth,
|
||||
windowWidth,
|
||||
} = getLayoutType();
|
||||
|
||||
export default () => {
|
||||
const [layoutType, setLayoutType] = useState(getLayoutType());
|
||||
|
||||
useEffect(() => {
|
||||
if (isWeb) {
|
||||
const handleResize = () => {
|
||||
setLayoutType(getLayoutType());
|
||||
};
|
||||
window.addEventListener("resize", handleResize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
return layoutType;
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useGlobal, useContext } from "reactn";
|
||||
|
||||
import firebase from "../config/firebase";
|
||||
import { checkBillingDetails } from "../helpers";
|
||||
|
||||
import { StripeEmbeddedContext } from "../providers/StripeEmbeddedProvider";
|
||||
import { useWebView } from "../providers/WebViewProvider";
|
||||
|
||||
import useLayoutType from "./useLayoutType";
|
||||
|
||||
const usePaymentSession = () => {
|
||||
const [, setIsLoading] = useGlobal("_isLoading");
|
||||
const [, setTooltip] = useGlobal("_tooltip");
|
||||
|
||||
const { isNative } = useLayoutType();
|
||||
const { setWebViewUrl } = useWebView();
|
||||
|
||||
const [currentProjectID] = useGlobal("currentProjectID");
|
||||
|
||||
const { setClientSecret } = useContext(StripeEmbeddedContext);
|
||||
|
||||
const onCreatePaymentSession = async ({
|
||||
numberOfCoin = 0,
|
||||
taskList = [],
|
||||
} = {}) => {
|
||||
checkBillingDetails({
|
||||
onValidBillingDetails: () => {
|
||||
triggerPayment({ numberOfCoin, taskList });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const triggerPayment = async ({ numberOfCoin = 0, taskList = [] }) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const { data } = await firebase
|
||||
.functions()
|
||||
.httpsCallable("coins-createPaymentSession")({
|
||||
numberOfCoin,
|
||||
taskList,
|
||||
projectID: currentProjectID,
|
||||
type: "CHECKOUT",
|
||||
isEmbedded: !isNative,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
if (isNative) {
|
||||
setWebViewUrl(data);
|
||||
} else {
|
||||
setClientSecret(data);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Erreur lors de la création du paiement");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setTooltip({
|
||||
type: "error",
|
||||
text: error.message,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
onCreatePaymentSession,
|
||||
};
|
||||
};
|
||||
|
||||
export default usePaymentSession;
|
||||
Reference in New Issue
Block a user