diff --git a/.firebaserc b/.firebaserc
new file mode 100644
index 00000000..e6c400b3
--- /dev/null
+++ b/.firebaserc
@@ -0,0 +1,5 @@
+{
+ "projects": {
+ "default": "osu-golf-drill-challenge-app"
+ }
+}
diff --git a/Contexts.js b/Contexts.js
deleted file mode 100644
index 6f1bdb92..00000000
--- a/Contexts.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { createContext } from "react";
-
-export const CurrentUserContext = createContext("c0nEyjaOMhItMQTLMY0X");
diff --git a/Utility.js b/Utility.js
index bc68759a..1b7e1f6b 100644
--- a/Utility.js
+++ b/Utility.js
@@ -33,6 +33,17 @@ export function refToID(ref) {
return ref["_key"] ? ref["_key"]["path"]["segments"].at(-1) : "bad ref";
}
+export function getUnique(array, field) {
+ const uniqueMap = new Map();
+ array.forEach((element) => {
+ const keyValue = element[field];
+ if (!uniqueMap.has(keyValue)) {
+ uniqueMap.set(keyValue, element);
+ }
+ });
+ return Array.from(uniqueMap.values());
+}
+
export function calculateAverageProxToHole(drillSubmissions) {
const userAverages = [];
drillSubmissions.forEach((submission) => {
@@ -106,5 +117,5 @@ export function createOutputData(inputValues, attemptData) {
return { ...object, sid: shotNum };
});
- console.log("Output Data: ", outputData);
+ //console.log("Output Data: ", outputData);
}
diff --git a/app/_layout.js b/app/_layout.js
index 594f8b05..ba491859 100644
--- a/app/_layout.js
+++ b/app/_layout.js
@@ -1,25 +1,30 @@
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Stack } from "expo-router";
import { useState } from "react";
-import { CurrentUserContext } from "~/Contexts";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+
+// Create a client
+const queryClient = new QueryClient();
export default function RootLayoutNav() {
const [currentUser, setCurrentUser] = useState("c0nEyjaOMhItMQTLMY0X");
+ const [currentTeam, setCurrentTeam] = useState("1");
- // Function to update the context value
- const updateCurrentUser = (newValue) => {
- setCurrentUser(newValue);
- };
return (
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
);
}
diff --git a/app/content/drill/[id]/attempts/[attempt].js b/app/content/drill/[id]/attempts/[attempt].js
index 8a056f2c..4be67d8f 100644
--- a/app/content/drill/[id]/attempts/[attempt].js
+++ b/app/content/drill/[id]/attempts/[attempt].js
@@ -1,6 +1,4 @@
import { useLocalSearchParams } from "expo-router";
-import { doc, getDoc } from "firebase/firestore";
-import { useEffect, useState } from "react";
import {
ScrollView,
StyleSheet,
@@ -11,19 +9,39 @@ import {
import { SafeAreaView } from "react-native-safe-area-context";
import ScatterChart from "react-native-scatter-chart";
import { numTrunc } from "~/Utility";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
import ShotAccordion from "~/components/shotAccordion";
-import db from "~/firebaseConfig";
+import { useAttempts } from "~/hooks/useAttempts";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
function Result() {
const drillId = useLocalSearchParams()["id"];
const attemptId = useLocalSearchParams()["attempt"];
- const [drillInfo, setDrillInfo] = useState({});
- const [attempt, setAttempt] = useState({});
+ const { width } = useWindowDimensions();
+
+ const {
+ data: drillInfo,
+ isLoading: drillInfoIsLoading,
+ error: drillInfoError,
+ } = useDrillInfo(drillId);
+
+ const {
+ data: attempt,
+ isLoading: attemptIsLoading,
+ error: attemptError,
+ } = useAttempts({ attemptId });
+
+ if (drillInfoIsLoading || attemptIsLoading) {
+ return ;
+ }
+
+ if (drillInfoError || attemptError) {
+ return ;
+ }
let dots = [];
if (
- Object.keys(drillInfo).length > 0 &&
- Object.keys(attempt).length > 0 &&
drillInfo["outputs"].includes("sideLanding") &&
drillInfo["outputs"].includes("carryDiff")
) {
@@ -32,29 +50,6 @@ function Result() {
value["carryDiff"],
]);
}
- const { width } = useWindowDimensions();
- useEffect(() => {
- // massive data fetching on refresh. May or may not get its data from cache
- let mainOutputAttempt = "";
- getDoc(doc(db, "teams", "1", "drills", drillId)).then((doc) => {
- // get drill data
- if (doc.exists()) {
- setDrillInfo(doc.data());
- console.log("got drill data", mainOutputAttempt);
- } else {
- // doc.data() will be undefined in this case
- console.log("No such document!");
- }
- });
- getDoc(doc(db, "teams", "1", "attempts", attemptId))
- .then((doc) => {
- setAttempt(doc.data());
- })
- .catch((error) => {
- console.log("Error getting documents: ", error);
- });
- return () => {};
- }, []);
return (
<>
diff --git a/app/content/drill/[id]/description.js b/app/content/drill/[id]/description.js
index 88379466..88b5c4c1 100644
--- a/app/content/drill/[id]/description.js
+++ b/app/content/drill/[id]/description.js
@@ -1,9 +1,23 @@
import { Link, useLocalSearchParams } from "expo-router";
import { Image, ScrollView } from "react-native";
import { Button, Text } from "react-native-paper";
+import Loading from "~/components/loading";
+import ErrorComponent from "../../../../components/errorComponent";
+import { useDrillInfo } from "../../../../hooks/useDrillInfo";
-export default function Description({ descData }) {
+export default function Description() {
const drillId = useLocalSearchParams()["id"];
+
+ const {
+ data: drillInfo,
+ error: drillInfoError,
+ isLoading: drillInfoIsLoading,
+ } = useDrillInfo(drillId);
+
+ if (drillInfoIsLoading) return ;
+
+ if (drillInfoError) return ;
+
return (
Description
- {descData.description}
+ {drillInfo["description"]}
;
- useEffect(() => {
- getDoc(drillsRef).then((document) => {
- setDrillData(document.data());
- });
- }, []);
+ if (drillInfoError) return ;
const tabComponent = () => {
switch (value) {
case "leaderboard":
return ;
case "description":
- return ;
+ return ;
case "stats":
return ;
}
@@ -46,7 +47,7 @@ export default function Index() {
}}
color={"#F24E1E"}
/>
-
+
{/* Tab system */}
diff --git a/app/content/drill/[id]/leaderboard.js b/app/content/drill/[id]/leaderboard.js
index 4eaad76a..dbe4f8be 100644
--- a/app/content/drill/[id]/leaderboard.js
+++ b/app/content/drill/[id]/leaderboard.js
@@ -1,119 +1,92 @@
import { Link, useLocalSearchParams, usePathname } from "expo-router";
-import {
- collection,
- doc,
- getDoc,
- getDocs,
- query,
- where,
-} from "firebase/firestore";
-import { useEffect, useState } from "react";
+import { useState } from "react";
import { ScrollView, View } from "react-native";
import { Avatar, Icon, List, Text } from "react-native-paper";
import { numTrunc } from "~/Utility";
-import db from "~/firebaseConfig";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
+import { useAttempts } from "~/hooks/useAttempts";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
+import { useUserInfo } from "~/hooks/useUserInfo";
export default function Leaderboard() {
const drillId = useLocalSearchParams()["id"];
- const [userInfo, setUserInfo] = useState({});
const currentPath = usePathname();
+ const [defaultMainOutputAttempt, setDefaultMainOutputAttempt] =
+ useState(true); //whether mainOutputAttempt is the default set on drills or has been changed by user
+ const [customMainOutputAttempt, setCustomMainOutputAttempt] = useState("did"); //What is the custom mainOutputAttempt in case defaultMainOutputAttempt is false
- const [drillLeaderboardAttempts, setDrillLeaderboardAttempts] = useState([]);
- const [drillInfo, setDrillInfo] = useState({});
+ const {
+ data: userInfo,
+ userIsLoading: userIsLoading,
+ userError: userError,
+ } = useUserInfo();
- useEffect(() => {
- // massive data fetching on refresh. May or may not get its data from cache
- let mainOutputAttempt = "";
- getDocs(collection(db, "teams", "1", "users")).then((querySnapshot) => {
- // get all attempts
- const newUserInfo = {};
- querySnapshot.forEach((doc) => {
- newUserInfo[doc.id] = doc.data();
- });
- setUserInfo(newUserInfo);
- console.log("got attempts", userInfo);
- });
- getDoc(doc(db, "teams", "1", "drills", drillId)).then((doc) => {
- // get drill data
- if (doc.exists()) {
- mainOutputAttempt = doc.data()["mainOutputAttempt"];
- setDrillInfo(doc.data());
- console.log("got drill data", mainOutputAttempt);
- } else {
- // doc.data() will be undefined in this case
- console.log("No such document!");
- }
- });
- getDocs(
- query(
- collection(db, "teams", "1", "attempts"),
- where("did", "==", drillId),
- ),
- )
- .then((querySnapshot) => {
- // get all attempts in drill and filter only the highest score for a user
- let newDrillAttempts = {};
- querySnapshot.forEach((doc) => {
- const data = doc.data();
- // console.log("data: ", data);
- if (!newDrillAttempts[data["uid"]])
- newDrillAttempts[data["uid"]] = {
- score: doc.data()[mainOutputAttempt],
- id: doc.id,
- };
- else if (
- newDrillAttempts[data["uid"]][mainOutputAttempt] <
- doc.data()[mainOutputAttempt]
- )
- newDrillAttempts[data["uid"]] = {
- score: doc.data()[mainOutputAttempt],
- id: doc.id,
- };
- });
- setDrillLeaderboardAttempts(
- Object.keys(newDrillAttempts).map((key) => {
- return {
- user: key,
- score: newDrillAttempts[key]["score"],
- id: newDrillAttempts[key]["id"],
- };
- }),
- );
- console.log("finished processing attempts", drillLeaderboardAttempts);
- })
- .catch((error) => {
- console.log("Error getting documents: ", error);
- });
- return () => {};
- }, []);
+ const {
+ data: drillInfo,
+ isLoading: drillIsLoading,
+ error: drillError,
+ } = useDrillInfo(drillId);
- const orderedLeaderboard = drillLeaderboardAttempts.sort(
- (a, b) => a["score"] - b["score"],
- );
+ const {
+ data: attempts,
+ isLoading: attemptIsLoading,
+ error: attemptError,
+ } = useAttempts({ drillId });
+
+ //console.log("userInfo: ", userInfo);
+ //console.log("drillInfo: ", drillInfo);
+
+ if (userIsLoading || drillIsLoading || attemptIsLoading) {
+ return ;
+ }
+
+ if (userError || drillError || attemptError) {
+ return ;
+ }
- const getUserInfo = (userId) => {
- return userInfo[userId] || { name: "Unknown", uid: "unknown" };
- };
+ // console.log("attempts: ", attempts);
+
+ const mainOutputAttempt = defaultMainOutputAttempt
+ ? drillInfo["mainOutputAttempt"]
+ : customMainOutputAttempt;
+
+ const drillLeaderboardAttempts = {};
+ for (const id in attempts) {
+ const entry = attempts[id];
+ // If this uid has not been seen before or the current score is higher, store it
+ if (
+ !drillLeaderboardAttempts[entry.uid] ||
+ drillLeaderboardAttempts[entry.uid][mainOutputAttempt] <
+ entry[mainOutputAttempt]
+ ) {
+ drillLeaderboardAttempts[entry.uid] = entry;
+ }
+ }
+
+ const orderedLeaderboard = Object.values(drillLeaderboardAttempts).sort(
+ (a, b) => a[mainOutputAttempt] - b[mainOutputAttempt],
+ );
- console.log(drillLeaderboardAttempts);
+ // console.log(orderedLeaderboard[0]);
return (
{orderedLeaderboard.map((attempt) => (
}
right={() => (
- {numTrunc(attempt.score)} ft
+ {numTrunc(attempt[mainOutputAttempt])} ft
)}
diff --git a/app/content/drill/[id]/statistics.js b/app/content/drill/[id]/statistics.js
index 9fc7ce1a..f4731427 100644
--- a/app/content/drill/[id]/statistics.js
+++ b/app/content/drill/[id]/statistics.js
@@ -1,51 +1,37 @@
import { useLocalSearchParams } from "expo-router";
-import { useContext, useEffect, useState } from "react";
-import {
- collection,
- doc,
- getDoc,
- getDocs,
- query,
- where,
-} from "firebase/firestore";
-import { CurrentUserContext } from "~/Contexts";
+import { useContext } from "react";
import BarChartScreen from "~/components/barChart";
-import db from "~/firebaseConfig";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+import { useAttempts } from "~/hooks/useAttempts";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
export default function Stat() {
const drillId = useLocalSearchParams()["id"];
- const [drillInfo, setDrillInfo] = useState("");
- const [drillAttempts, setDrillAttempts] = useState([]);
const userId = useContext(CurrentUserContext)["currentUser"];
- useEffect(() => {
- // massive data fetching on refresh. May or may not get its data from cache
- getDoc(doc(db, "teams", "1", "drills", drillId)).then((doc) => {
- // get drill data
- if (doc.exists()) {
- setDrillInfo(doc.data());
- } else {
- // doc.data() will be undefined in this case
- console.log("No such document!");
- }
- });
- getDocs(
- query(
- collection(db, "teams", "1", "attempts"),
- where("did", "==", drillId),
- where("uid", "==", userId),
- ),
- )
- .then((querySnapshot) => {
- // get all attempts in drill and filter only the highest score for a user
- let newDrillAttempts = [];
- querySnapshot.forEach((doc) => newDrillAttempts.push(doc.data()));
- setDrillAttempts(newDrillAttempts);
- })
- .catch((error) => {
- console.log("Error getting documents: ", error);
- });
- return () => {};
- }, []);
+
+ const {
+ data: drillInfo,
+ isLoading: drillInfoIsLoading,
+ drillInfoError,
+ } = useDrillInfo(drillId);
+
+ const {
+ data: drillAttempts,
+ isLoading: drillAttemptsIsLoading,
+ error: drillAttemptsError,
+ } = useAttempts({ drillId, userId });
+
+ if (drillInfoIsLoading || drillAttemptsIsLoading) {
+ return ;
+ }
+
+ if (drillInfoError || drillAttemptsError) {
+ return ;
+ }
+ // console.log(drillAttempts);
+
return ;
}
diff --git a/app/content/drill/index.js b/app/content/drill/index.js
index 70e2bdd3..ee694946 100644
--- a/app/content/drill/index.js
+++ b/app/content/drill/index.js
@@ -1,33 +1,28 @@
import { Link, useNavigation } from "expo-router";
-import React, { useEffect } from "react";
-import { RefreshControl, ScrollView, StyleSheet } from "react-native";
+import { ScrollView, StyleSheet } from "react-native";
import { Appbar, List, PaperProvider } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
-import { collection, getDocs } from "firebase/firestore";
-import db from "~/firebaseConfig";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
export default function Index() {
- const [drills, setDrills] = React.useState([]); // [{}
- const drillsRef = collection(db, "teams", "1", "drills");
const navigation = useNavigation();
- const [refreshing, setRefreshing] = React.useState(false);
+ const {
+ data: drillInfo,
+ error: drillInfoError,
+ isLoading: drillInfoIsLoading,
+ } = useDrillInfo();
- useEffect(() => {
- getDocs(drillsRef).then((querySnapshot) => {
- let newDrills = [];
- querySnapshot.forEach((doc) => {
- newDrills.push(doc.data());
- });
- setDrills(newDrills);
- setRefreshing(false);
- });
- }, [refreshing]);
+ if (drillInfoIsLoading) {
+ return ;
+ }
- const onRefresh = React.useCallback(() => {
- setRefreshing(true);
- }, []);
+ if (drillInfoError) {
+ return ;
+ }
return (
@@ -37,9 +32,8 @@ export default function Index() {
-
- {drills.map((drill) => (
+ {Object.values(drillInfo).map((drill) => (
{
- // massive data fetching on refresh. May or may not get its data from cache
- getDoc(doc(db, "teams", "1", "drills", drillId)).then((doc) => {
- // get drill data
- if (doc.exists()) {
- setDrillInfo(doc.data());
- console.log("got drill data", drillInfo);
- } else {
- // doc.data() will be undefined in this case
- console.log("No such document!");
- }
- });
- getDocs(
- query(
- collection(db, "teams", "1", "attempts"),
- where("did", "==", drillId),
- where("uid", "==", userId),
- ),
- )
- .then((querySnapshot) => {
- // get all attempts in drill and filter only the highest score for a user
- let newDrillAttempts = [];
- querySnapshot.forEach((doc) => newDrillAttempts.push(doc.data()));
- setDrillAttempts(newDrillAttempts);
- })
- .catch((error) => {
- console.log("Error getting documents: ", error);
- });
- return () => {};
- }, []);
+
+ const {
+ data: drillInfo,
+ isLoading: drillInfoIsLoading,
+ drillInfoError,
+ } = useDrillInfo(drillId);
+
+ const {
+ data: drillAttempts,
+ isLoading: drillAttemptsIsLoading,
+ error: drillAttemptsError,
+ } = useAttempts({ drillId, userId });
+
+ if (drillInfoIsLoading || drillAttemptsIsLoading) {
+ return ;
+ }
+
+ if (drillInfoError || drillAttemptsError) {
+ return ;
+ }
+
return (
diff --git a/app/content/profile/index.js b/app/content/profile/index.js
index 72241fd9..f558c94f 100644
--- a/app/content/profile/index.js
+++ b/app/content/profile/index.js
@@ -1,51 +1,49 @@
import { useNavigation } from "expo-router";
-import {
- collection,
- doc,
- getDoc,
- getDocs,
- query,
- where,
-} from "firebase/firestore";
-import { useContext, useEffect, useState } from "react";
+import { useContext } from "react";
import { ScrollView, StyleSheet, Text, View } from "react-native";
import { Appbar, PaperProvider } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
-import { CurrentUserContext } from "~/Contexts";
+import { getUnique } from "~/Utility";
import DrillCard from "~/components/drillCard";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
import ProfileCard from "~/components/profileCard";
-import db from "~/firebaseConfig";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+import { useAttempts } from "~/hooks/useAttempts";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
+import { useUserInfo } from "~/hooks/useUserInfo";
function Index(props) {
const navigation = useNavigation();
- const [userData, setUserData] = useState({});
const userId = useContext(CurrentUserContext)["currentUser"];
- const [drills, setDrills] = useState({});
+ const {
+ data: userData,
+ userError: userError,
+ userIsLoading: userIsLoading,
+ } = useUserInfo(userId);
+ const {
+ data: attempts,
+ error: attemptsError,
+ isLoading: attemptsIsLoading,
+ } = useAttempts({ userId });
- useEffect(() => {
- let uniqueDrills = new Set();
- getDoc(doc(db, "teams", "1", "users", userId)).then((doc) => {
- setUserData(doc.data());
- });
- getDocs(
- query(collection(db, "teams", "1", "attempts")),
- where("uid", "==", userId),
- ).then((querySnapshot) => {
- querySnapshot.forEach((doc) => {
- uniqueDrills.add(doc.data()["did"]);
- });
- });
- getDocs(
- query(collection(db, "teams", "1", "drills")),
- where("did", "in", uniqueDrills),
- ).then((querySnapshot) => {
- let newDrills = {};
- querySnapshot.forEach((doc) => {
- newDrills[doc.id] = doc.data();
- });
- setDrills(newDrills);
- });
- }, []);
+ const {
+ data: drillInfo,
+ error: drillInfoError,
+ isLoading: drillInfoIsLoading,
+ } = useDrillInfo();
+
+ if (userIsLoading || drillInfoIsLoading || attemptsIsLoading) {
+ return ;
+ }
+
+ if (userError || drillInfoError || attemptsError) {
+ return (
+
+ );
+ }
+
+ const uniqueDrills = getUnique(attempts, "did");
return (
@@ -69,11 +67,12 @@ function Index(props) {
Drill History
- {Object.keys(drills).length > 0 ? (
- Object.keys(drills).map((drillId) => {
+ {uniqueDrills.length > 0 ? (
+ uniqueDrills.map((drill) => {
+ const drillId = drill["did"];
return (
diff --git a/app/content/profile/statistics.js b/app/content/profile/statistics.js
index dd4512a0..21b557b4 100644
--- a/app/content/profile/statistics.js
+++ b/app/content/profile/statistics.js
@@ -2,11 +2,6 @@ import { PaperProvider, Text } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
//This is for the list of drills
export default function Statistics() {
- /*React.useEffect(() => {
- navigation.getParent()?.setOptions({
- tabBarStyle: { display: 'none' },
- });
- })*/
return (
{
- getDocs(usersRef).then((querySnapshot) => {
- let newUsers = [];
- querySnapshot.forEach((doc) => {
- newUsers.push(doc.data());
- });
- setUsers(newUsers);
- });
- }, []);
+ const { data: userInfo, userIsLoading, userError } = useUserInfo();
const [searchQuery, setSearchQuery] = React.useState("");
const onChangeSearch = (query) => setSearchQuery(query);
- const foundUsers = users.filter((user) =>
- user.name.toLowerCase().includes(searchQuery.toLowerCase()),
- );
-
- console.log("Found: ", foundUsers);
+ //console.log("Found: ", foundUsers);
// ref
const bottomSheetModalRef = useRef(null);
@@ -65,9 +48,17 @@ function Index() {
bottomSheetModalRef.current?.present();
}, []);
const handleSheetChanges = useCallback((index) => {
- console.log("handleSheetChanges", index);
+ //console.log("handleSheetChanges", index);
}, []);
+ if (userIsLoading) return ;
+
+ if (userError) return ;
+
+ const foundUsers = Object.values(userInfo).filter((user) =>
+ user.name.toLowerCase().includes(searchQuery.toLowerCase()),
+ );
+
return (
- {Object.keys(users).length} members
+ {Object.keys(userInfo).length} members
;
+ }
+
+ if (drillInfoError || drillAttemptsError) {
+ return ;
+ }
- useEffect(() => {
- // massive data fetching on refresh. May or may not get its data from cache
- getDoc(doc(db, "teams", "1", "drills", drillId)).then((doc) => {
- // get drill data
- if (doc.exists()) {
- setDrillInfo(doc.data());
- } else {
- // doc.data() will be undefined in this case
- console.log("No such document!");
- }
- });
- getDocs(
- query(
- collection(db, "teams", "1", "attempts"),
- where("did", "==", drillId),
- where("uid", "==", userId),
- ),
- )
- .then((querySnapshot) => {
- // get all attempts in drill and filter only the highest score for a user
- let newDrillAttempts = [];
- querySnapshot.forEach((doc) => newDrillAttempts.push(doc.data()));
- setDrillAttempts(newDrillAttempts);
- })
- .catch((error) => {
- console.log("Error getting documents: ", error);
- });
- return () => {};
- }, []);
return (
diff --git a/app/content/team/users/[user]/index.js b/app/content/team/users/[user]/index.js
index f89ccacd..55c9c211 100644
--- a/app/content/team/users/[user]/index.js
+++ b/app/content/team/users/[user]/index.js
@@ -1,52 +1,49 @@
import { useLocalSearchParams, useNavigation } from "expo-router";
-import {
- collection,
- doc,
- getDoc,
- getDocs,
- query,
- where,
-} from "firebase/firestore";
-import { useEffect, useState } from "react";
import { ScrollView, StyleSheet, Text, View } from "react-native";
import { Appbar, PaperProvider } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
+import { refToID } from "~/Utility";
import DrillCard from "~/components/drillCard";
+import ErrorComponent from "~/components/errorComponent";
+import Loading from "~/components/loading";
import ProfileCard from "~/components/profileCard";
-import db from "~/firebaseConfig";
-import { refToID } from "~/Utility";
+import { useAttempts } from "~/hooks/useAttempts";
+import { useDrillInfo } from "~/hooks/useDrillInfo";
+import { useUserInfo } from "~/hooks/useUserInfo";
+import { getUnique } from "../../../../../Utility";
function Index(props) {
- const user_id = useLocalSearchParams()["user"];
+ const userId = useLocalSearchParams()["user"];
const navigation = useNavigation();
- const [drills, setDrills] = useState({});
- const [userData, setUserData] = useState({});
- console.log("userData", userData);
- useEffect(() => {
- let uniqueDrills = new Set();
- getDoc(doc(db, "teams", "1", "users", user_id)).then((doc) => {
- setUserData(doc.data());
- });
- getDocs(
- query(collection(db, "teams", "1", "attempts")),
- where("uid", "==", user_id),
- ).then((querySnapshot) => {
- querySnapshot.forEach((doc) => {
- uniqueDrills.add(doc.data()["did"]);
- });
+ const {
+ data: userData,
+ userError: userError,
+ userIsLoading: userIsLoading,
+ } = useUserInfo(userId);
+
+ const {
+ data: attempts,
+ error: attemptsError,
+ isLoading: attemptsIsLoading,
+ } = useAttempts({ userId });
+
+ const {
+ data: drillInfo,
+ error: drillInfoError,
+ isLoading: drillInfoIsLoading,
+ } = useDrillInfo();
+
+ if (userIsLoading || drillInfoIsLoading || attemptsIsLoading) {
+ return ;
+ }
+
+ if (userError || drillInfoError || attemptsError) {
+ return (
+
+ );
+ }
- getDocs(
- query(collection(db, "teams", "1", "drills")),
- where("did", "in", uniqueDrills),
- ).then((querySnapshot) => {
- let newDrills = {};
- querySnapshot.forEach((doc) => {
- newDrills[doc.id] = doc.data();
- });
- setDrills(newDrills);
- });
- });
- }, []);
+ const uniqueDrills = getUnique(attempts, "did");
return (
@@ -68,19 +65,22 @@ function Index(props) {
Drills
- {Object.keys(drills).length > 0 ? (
- Object.keys(drills).map((drillId) => (
-
- ))
+ {uniqueDrills.length > 0 ? (
+ uniqueDrills.map((drill) => {
+ const drillId = drill["did"];
+ return (
+
+ );
+ })
) : (
No drills attempted yet
)}
diff --git a/app/segments/drill/[id]/submission/input.js b/app/segments/drill/[id]/submission/input.js
index 992cb08a..f98ad0e9 100644
--- a/app/segments/drill/[id]/submission/input.js
+++ b/app/segments/drill/[id]/submission/input.js
@@ -65,7 +65,7 @@ export default function Input({ inputValues, setInputValues }) {
labelStyle={styles.buttonText}
mode="contained-tonal"
onPress={() => {
- console.log("Pressed Next Shot");
+ //console.log("Pressed Next Shot");
handleNextShotButtonClick();
}}
>
@@ -79,7 +79,7 @@ export default function Input({ inputValues, setInputValues }) {
labelStyle={styles.buttonText}
mode="contained-tonal"
onPress={() => {
- console.log("Pressed Back to Latest");
+ //console.log("Pressed Back to Latest");
setShotIndex(currentShot);
}}
>
@@ -109,7 +109,7 @@ export default function Input({ inputValues, setInputValues }) {
setShotIndex(shotIndex + 1);
setCurrentShot(currentShot + 1);
} else {
- console.log("Not all input fields entered!");
+ //console.log("Not all input fields entered!");
setEmptyInputBannerVisable(true);
}
};
@@ -130,7 +130,7 @@ export default function Input({ inputValues, setInputValues }) {
navigationBottomSheetModalRef.current?.present();
}, []);
const handleNavigationSheetChanges = useCallback((index) => {
- console.log("handleSheetChanges", index);
+ //console.log("handleSheetChanges", index);
}, []);
/***** Description Bottom Sheet Stuff *****/
@@ -142,7 +142,7 @@ export default function Input({ inputValues, setInputValues }) {
descriptionBottomSheetModalRef.current?.present();
}, []);
const handleDesciptionSheetChanges = useCallback((index) => {
- console.log("handleDesciptionSheetChanges", index);
+ //console.log("handleDesciptionSheetChanges", index);
}, []);
/***** Leave drill Dialog Stuff *****/
@@ -244,9 +244,9 @@ export default function Input({ inputValues, setInputValues }) {
onPress={() => {
//this loop is a test to see if inputs are maintained in state
for (let i = 0; i < AttemptData.shots.length; i++) {
- console.log("InputValue[", i, "]: ", inputValues[i]);
+ //console.log("InputValue[", i, "]: ", inputValues[i]);
}
- console.log(inputValues);
+ //console.log(inputValues);
}}
>
Log Input State Status
@@ -275,7 +275,7 @@ export default function Input({ inputValues, setInputValues }) {
{
- console.log("Clicked on ", id);
+ //console.log("Clicked on ", id);
setShotIndex(id);
}}
inputs={item.inputs}
@@ -341,7 +341,7 @@ export default function Input({ inputValues, setInputValues }) {
{
- console.log("Pressed View All Shots");
+ //console.log("Pressed View All Shots");
handlePresentNavigationModalPress();
}}
>
diff --git a/components/barChart.js b/components/barChart.js
index f0aff71c..3625ee06 100644
--- a/components/barChart.js
+++ b/components/barChart.js
@@ -203,7 +203,7 @@ export default function BarChartScreen({ drillData, drillInfo }) {
},
bottomTextContainer: {
flexDirection: "row",
- justifyContent: "space-between",
+ justifyContent: "flex-start",
marginBottom: 13,
marginLeft: 8,
marginRight: 8,
@@ -276,11 +276,19 @@ export default function BarChartScreen({ drillData, drillInfo }) {
- {dateString}
-
+
+ {dateString}
+
+
MA: {numTrunc(movingAvgData[selected])}
- SG: {numTrunc(data[selected])}
+
+ SG: {numTrunc(data[selected])}
+
{drillDataSorted[selected]["shots"].map((shot) => (
diff --git a/components/drillCard.js b/components/drillCard.js
index b61382ac..c1d8c167 100644
--- a/components/drillCard.js
+++ b/components/drillCard.js
@@ -2,6 +2,7 @@ import { Link } from "expo-router";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
function DrillCard(props) {
+ console.log(props);
return (
diff --git a/components/errorComponent.js b/components/errorComponent.js
new file mode 100644
index 00000000..888996f0
--- /dev/null
+++ b/components/errorComponent.js
@@ -0,0 +1,16 @@
+import { PaperProvider, Text } from "react-native-paper";
+import { SafeAreaView } from "react-native-safe-area-context";
+
+function ErrorComponent({ message }) {
+ const displayMessage =
+ message.constructor === Array ? message.join(", ") : message;
+ return (
+
+
+ An error has occurred: {displayMessage}
+
+
+ );
+}
+
+export default ErrorComponent;
diff --git a/components/loading.js b/components/loading.js
new file mode 100644
index 00000000..7e6ce652
--- /dev/null
+++ b/components/loading.js
@@ -0,0 +1,14 @@
+import { PaperProvider, Text } from "react-native-paper";
+import { SafeAreaView } from "react-native-safe-area-context";
+
+function Loading() {
+ return (
+
+
+ Loading...
+
+
+ );
+}
+
+export default Loading;
diff --git a/components/shotAccordion.js b/components/shotAccordion.js
index 36c21ed9..3e2187ef 100644
--- a/components/shotAccordion.js
+++ b/components/shotAccordion.js
@@ -76,22 +76,34 @@ function ShotAccordion(props) {
},
}}
title={
-
-
+
+
Shot: {props.shot["sid"]}/
{props.total}
-
+
Target:{" "}
{props.shot["target"]} yd
-
+
SG:{" "}
{numTrunc(props.shot[props.drillInfo["mainOutputShot"]])}
}
- style={styles.container}
+ style={{
+ backgroundColor: "#f5f5f5",
+ borderWidth: 1,
+ borderColor: "#ddd",
+ borderRadius: 8,
+ }}
>
{},
+ updateCurrentTeam: () => {},
+});
diff --git a/firebaseConfig.js b/firebaseConfig.js
index 55226fd4..876f5686 100644
--- a/firebaseConfig.js
+++ b/firebaseConfig.js
@@ -22,4 +22,6 @@ const firebaseConfig = {
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
+// connectFirestoreEmulator(db, "localhost", 8080);
+
module.exports = db;
diff --git a/generate_drill_data.py b/generate_drill_data.py
index 50ef4304..e9ecba56 100644
--- a/generate_drill_data.py
+++ b/generate_drill_data.py
@@ -3,8 +3,11 @@
import math
import firebase_admin
from firebase_admin import firestore
+import os
# Application Default credentials are automatically created.
+# os.environ["FIRESTORE_EMULATOR_HOST"] = "localhost:8080"
+
app = firebase_admin.initialize_app()
db = firestore.client()
@@ -26,9 +29,12 @@ def lookup_round_down(value, lookup_keys, lookup_values):
line_test = ["8", "9", "PW", "9", "8", "7", "8", "9", "PW", "9", "8", "7", "8", "9", "PW", "9", "8", "7", "8", "9"]
+users = ["rcnS0atnVgt4svjVK0ZS","dkjydFrmyi9dRK9Jj2Su","TaSveOyBkVaK012r6meC","c0nEyjaOMhItMQTLMY0X","8mTnNFsMQYlTDeaQmluZ","8j6vfO5xpIdZF9dUAAV8oizr60v1","8aUSErrZSHWEsgRYIedq","6r2BOnaLTaiDgPMd7RWa"]
+
+collection_ref = db.collection("teams").document("1").collection("attempts")
# Function to generate random data for one submission
-def generate_submission(submission_id):
+def generate_submission(user_id):
# Unix timestamp for the submission
time_stamp = random.randint(1600000000, 1800000000)
@@ -68,11 +74,19 @@ def generate_submission(submission_id):
strokes_gained_total += strokes_gained
shots.append(shot)
+
+ # Generate a new document reference with an auto-generated ID
+ doc_ref = collection_ref.document()
+
+ # Get the auto-generated ID
+ doc_id = doc_ref.id
+
# One submission
submission = {
"time": time_stamp,
- "uid": "c0nEyjaOMhItMQTLMY0X",
+ "uid": user_id,
"did": "SpvYyY94HaulVH2zmVyM",
+ "id": doc_id,
"strokesGained": strokes_gained_total,
"strokesGainedAverage": strokes_gained_total / num_shots,
"carryDiffAverage": carry_diff_total / num_shots,
@@ -80,10 +94,11 @@ def generate_submission(submission_id):
"proxHoleAverage": prox_hole_total / num_shots,
"shots": shots
}
- db.collection("teams").document("1").collection("attempts").document().set(submission)
+
+ doc_ref.set(submission)
return submission
-def generate_submission_line(submission_id):
+def generate_submission_line(user_id):
# Unix timestamp for the submission
time_stamp = random.randint(1600000000, 1800000000)
@@ -103,21 +118,31 @@ def generate_submission_line(submission_id):
side_landing_total += side_landing
shots.append(shot)
+
+ # Generate a new document reference with an auto-generated ID
+ doc_ref = collection_ref.document()
+
+ # Get the auto-generated ID
+ doc_id = doc_ref.id
+
# One submission
submission = {
"time": time_stamp,
- "uid": "c0nEyjaOMhItMQTLMY0X",
+ "uid": user_id,
"did": "YtCsaxzscFScnpZYmnKI",
+ "id": doc_id,
"sideLandingTotal": side_landing_total,
"sideLandingAverage": side_landing_total / len(shots),
"shots": shots
}
- db.collection("teams").document("1").collection("attempts").document().set(submission)
+
+ doc_ref.set(submission)
return submission
# Generate 100 submissions
-submissions = [generate_submission(i) for i in range(100)]
-
-# Print the submissions without indentation or new lines
-print(submissions)
+for user_id in users:
+ for i in range(random.randint(50, 150)):
+ submission = generate_submission(user_id)
+ for i in range(random.randint(50, 150)):
+ submission = generate_submission_line(user_id)
diff --git a/hooks/useAttempts.js b/hooks/useAttempts.js
new file mode 100644
index 00000000..7251a1be
--- /dev/null
+++ b/hooks/useAttempts.js
@@ -0,0 +1,49 @@
+import { useQuery } from "@tanstack/react-query";
+import {
+ collection,
+ doc,
+ getDoc,
+ getDocs,
+ query,
+ where,
+} from "firebase/firestore";
+import { useContext } from "react";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+import db from "~/firebaseConfig";
+
+//this code scares me
+export const useAttempts = ({
+ attemptId = null,
+ userId = null,
+ drillId = null,
+}) => {
+ const teamId = useContext(CurrentUserContext).currentTeam;
+ const { data, error, isLoading } = useQuery({
+ queryKey: ["attempts", teamId, { attemptId, userId, drillId }],
+ queryFn: async () => {
+ if (attemptId) {
+ const querySnapshot = await getDoc(
+ doc(db, "teams", teamId, "attempts", attemptId),
+ );
+ return querySnapshot.data();
+ } else {
+ let q = query(collection(db, "teams", teamId, "attempts"));
+ if (drillId) {
+ q = query(q, where("did", "==", drillId));
+ }
+ if (userId) {
+ q = query(q, where("uid", "==", userId));
+ }
+ const querySnapshot = await getDocs(q);
+
+ return querySnapshot.docs.map((doc) => doc.data());
+ }
+ },
+ });
+
+ return {
+ data,
+ error,
+ isLoading,
+ };
+};
diff --git a/hooks/useDrillInfo.js b/hooks/useDrillInfo.js
new file mode 100644
index 00000000..d05b2e05
--- /dev/null
+++ b/hooks/useDrillInfo.js
@@ -0,0 +1,37 @@
+import { useQuery } from "@tanstack/react-query";
+import { collection, doc, getDoc, getDocs } from "firebase/firestore";
+import { useContext } from "react";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+import db from "~/firebaseConfig";
+
+export const useDrillInfo = (drillId = null) => {
+ const teamId = useContext(CurrentUserContext).currentTeam;
+ const { data, error, isLoading } = useQuery({
+ queryKey: drillId ? ["drillInfo", teamId, drillId] : ["drillInfo", teamId],
+ queryFn: async () => {
+ if (drillId) {
+ // Fetch specific drill info
+ const docSnapshot = await getDoc(
+ doc(db, "teams", teamId, "drills", drillId),
+ );
+ return docSnapshot.data();
+ } else {
+ // Fetch all drills info
+ const newDrillInfo = {};
+ const querySnapshot = await getDocs(
+ collection(db, "teams", teamId, "drills"),
+ );
+ querySnapshot.forEach((doc) => {
+ newDrillInfo[doc.id] = doc.data();
+ });
+ return newDrillInfo;
+ }
+ },
+ });
+
+ return {
+ data,
+ error,
+ isLoading,
+ };
+};
diff --git a/hooks/useUserInfo.js b/hooks/useUserInfo.js
new file mode 100644
index 00000000..b88f494a
--- /dev/null
+++ b/hooks/useUserInfo.js
@@ -0,0 +1,36 @@
+import { useQuery } from "@tanstack/react-query";
+import { collection, doc, getDoc, getDocs } from "firebase/firestore";
+import { useContext } from "react";
+import { CurrentUserContext } from "~/contexts/CurrentUserContext";
+import db from "~/firebaseConfig";
+
+export const useUserInfo = (userId = null) => {
+ const teamId = useContext(CurrentUserContext).currentTeam;
+
+ const { data, error, isLoading } = useQuery({
+ queryKey: userId ? ["user", teamId, userId] : ["users", teamId],
+ queryFn: async () => {
+ if (userId) {
+ const querySnapshot = await getDoc(
+ doc(db, "teams", teamId, "users", userId),
+ );
+ return querySnapshot.data();
+ } else {
+ const newUserInfo = {};
+ const querySnapshot = await getDocs(
+ collection(db, "teams", teamId, "users"),
+ );
+ querySnapshot.forEach((doc) => {
+ newUserInfo[doc.id] = doc.data();
+ });
+ return newUserInfo;
+ }
+ },
+ });
+
+ return {
+ data,
+ userError: error,
+ userIsLoading: isLoading,
+ };
+};
diff --git a/package.json b/package.json
index e6994cab..bfe0e101 100644
--- a/package.json
+++ b/package.json
@@ -8,12 +8,14 @@
"ios": "expo start --ios",
"web": "expo start --web",
"pretty": "prettier --write .",
- "python": "./venv/bin/python"
+ "python": "./venv/bin/python",
+ "firestore": "firebase emulators:start --only firestore"
},
"dependencies": {
"@expo/ngrok": "^4.1.0",
"@expo/webpack-config": "^19.0.0",
"@gorhom/bottom-sheet": "^4",
+ "@tanstack/react-query": "^5.24.1",
"babel-plugin-root-import": "^6.6.0",
"d3-scale": "^4.0.2",
"d3-shape": "^3.2.0",
@@ -42,6 +44,7 @@
},
"devDependencies": {
"@babel/core": "^7.20.0",
+ "@tanstack/eslint-plugin-query": "^5.20.1",
"prettier": "3.2.5",
"prettier-plugin-organize-imports": "^3.2.4"
},
diff --git a/yarn.lock b/yarn.lock
index 40ba96e0..cc389796 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1191,6 +1191,13 @@
dependencies:
"@types/hammerjs" "^2.0.36"
+"@eslint-community/eslint-utils@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
"@expo/bunyan@4.0.0", "@expo/bunyan@^4.0.0":
version "4.0.0"
resolved "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz"
@@ -2628,6 +2635,25 @@
dependencies:
defer-to-connect "^2.0.0"
+"@tanstack/eslint-plugin-query@^5.20.1":
+ version "5.20.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.20.1.tgz#861afedd7cde6b98c88cf86a5923bb659122e7af"
+ integrity sha512-oIp7Wh90KHOm1FKCvcv87fiD2H96xo/crFrlhbvqBzR2f0tMEGOK/ANKMGNFQprd6BT6lyZhQPlOEkFdezsjIg==
+ dependencies:
+ "@typescript-eslint/utils" "^6.20.0"
+
+"@tanstack/query-core@5.24.1":
+ version "5.24.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.24.1.tgz#d40928dec22b47df97fb2648e8c499772e8d7eb2"
+ integrity sha512-DZ6Nx9p7BhjkG50ayJ+MKPgff+lMeol7QYXkvuU5jr2ryW/4ok5eanaS9W5eooA4xN0A/GPHdLGOZGzArgf5Cg==
+
+"@tanstack/react-query@^5.24.1":
+ version "5.24.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.24.1.tgz#bcb913febe0d813cec1fda7783298d07aa998b20"
+ integrity sha512-4+09JEdO4d6+Gc8Y/g2M/MuxDK5IY0QV8+2wL2304wPKJgJ54cBbULd3nciJ5uvh/as8rrxx6s0mtIwpRuGd1g==
+ dependencies:
+ "@tanstack/query-core" "5.24.1"
+
"@trysound/sax@0.2.0":
version "0.2.0"
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
@@ -2768,7 +2794,7 @@
dependencies:
"@types/istanbul-lib-report" "*"
-"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.15"
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
@@ -2826,6 +2852,11 @@
resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz"
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
+"@types/semver@^7.5.0":
+ version "7.5.8"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
+ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+
"@types/send@*":
version "0.17.4"
resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz"
@@ -2895,6 +2926,54 @@
dependencies:
"@types/yargs-parser" "*"
+"@typescript-eslint/scope-manager@6.21.0":
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1"
+ integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==
+ dependencies:
+ "@typescript-eslint/types" "6.21.0"
+ "@typescript-eslint/visitor-keys" "6.21.0"
+
+"@typescript-eslint/types@6.21.0":
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d"
+ integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==
+
+"@typescript-eslint/typescript-estree@6.21.0":
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46"
+ integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==
+ dependencies:
+ "@typescript-eslint/types" "6.21.0"
+ "@typescript-eslint/visitor-keys" "6.21.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ minimatch "9.0.3"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/utils@^6.20.0":
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134"
+ integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@types/json-schema" "^7.0.12"
+ "@types/semver" "^7.5.0"
+ "@typescript-eslint/scope-manager" "6.21.0"
+ "@typescript-eslint/types" "6.21.0"
+ "@typescript-eslint/typescript-estree" "6.21.0"
+ semver "^7.5.4"
+
+"@typescript-eslint/visitor-keys@6.21.0":
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47"
+ integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==
+ dependencies:
+ "@typescript-eslint/types" "6.21.0"
+ eslint-visitor-keys "^3.4.1"
+
"@urql/core@2.3.6", "@urql/core@>=2.3.1":
version "2.3.6"
resolved "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz"
@@ -4788,6 +4867,11 @@ eslint-scope@5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
esprima@^4.0.0, esprima@~4.0.0:
version "4.0.1"
resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
@@ -5499,7 +5583,7 @@ globals@^11.1.0:
resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-globby@^11.0.1:
+globby@^11.0.1, globby@^11.1.0:
version "11.1.0"
resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
@@ -7008,6 +7092,13 @@ minimalistic-assert@^1.0.0:
dependencies:
brace-expansion "^1.1.7"
+minimatch@9.0.3, minimatch@^9.0.1:
+ version "9.0.3"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimatch@^5.0.1:
version "5.1.6"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
@@ -7015,13 +7106,6 @@ minimatch@^5.0.1:
dependencies:
brace-expansion "^2.0.1"
-minimatch@^9.0.1:
- version "9.0.3"
- resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz"
- integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
- dependencies:
- brace-expansion "^2.0.1"
-
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
@@ -9356,6 +9440,11 @@ traverse@~0.6.6:
resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz"
integrity sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==
+ts-api-utils@^1.0.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b"
+ integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==
+
ts-interface-checker@^0.1.9:
version "0.1.13"
resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz"