diff --git a/app/content/profile/index.js b/app/content/profile/index.js index e6764a80..e69ba85b 100644 --- a/app/content/profile/index.js +++ b/app/content/profile/index.js @@ -1,4 +1,5 @@ import { MaterialIcons } from "@expo/vector-icons"; +import { KeyboardAvoiderScrollView } from "@good-react-native/keyboard-avoider"; import { BottomSheetModalProvider, BottomSheetScrollView, @@ -320,150 +321,157 @@ function Index() { }} > - {/* Profile Picture */} - { - try { - await handleImageUpload( - setImageUploading, - showSnackBar, - getPfpName(currentTeamId, userId), - userRef, - profilePicSize, - profilePicSize, - ); - await invalidateMultipleKeys(queryClient, [["userInfo"]]); - } catch (e) { - console.log(e); - showDialog("Error", getErrorString(e)); - } - }} - > - - {imageUploading ? ( - - ) : ( - - )} - - - - - - {/* Display Name */} - - {userData.name} - + + + {/* Profile Picture */} + { + try { + await handleImageUpload( + setImageUploading, + showSnackBar, + getPfpName(currentTeamId, userId), + userRef, + profilePicSize, + profilePicSize, + ); + await invalidateMultipleKeys(queryClient, [["userInfo"]]); + } catch (e) { + console.log(e); + showDialog("Error", getErrorString(e)); + } + }} + > + + {imageUploading ? ( + + ) : ( + + )} + + + + + + {/* Display Name */} + + {userData.name} + - {/* Display Email */} - - {email} - - - {/* Name Update input field */} - - Update your name - - setNewName(text)} - placeholder="Update your name" - /> - - {/* Change Password Button */} - - Change Password - { - resetForm(); - setPasswordInputVisible(newValue); - }} - theme={{ - colors: { - primary: themeColors.accent, - }, - }} - /> - + {/* Display Email */} + + {email} + - {/* Password Input Field */} - {passwordInputVisible && ( - <> - - + {/* Name Update input field */} + + + Update your name + + setNewName(text)} + placeholder="Update your name" /> - - )} - {/* Save Button */} - + {/* Change Password Button */} + + + Change Password + + { + resetForm(); + setPasswordInputVisible(newValue); + }} + theme={{ + colors: { + primary: themeColors.accent, + }, + }} + /> + + + {/* Password Input Field */} + {passwordInputVisible && ( + <> + + + + + )} + + {/* Save Button */} + - {/* Sign Out Button */} - - Sign Out - + {/* Sign Out Button */} + + Sign Out + + + {uniqueDrills.length > 0 && userData.role === "player" ? ( diff --git a/app/content/team/users/[user]/index.js b/app/content/team/users/[user]/index.js index 4d934265..a06d86c6 100644 --- a/app/content/team/users/[user]/index.js +++ b/app/content/team/users/[user]/index.js @@ -3,7 +3,14 @@ import { useLocalSearchParams, useNavigation } from "expo-router"; import { doc, setDoc, updateDoc } from "firebase/firestore"; import { useState } from "react"; import { FlatList, View } from "react-native"; -import { Appbar, Divider, Menu, SegmentedButtons } from "react-native-paper"; +import { + ActivityIndicator, + Appbar, + Divider, + Menu, + SegmentedButtons, + Text, +} from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; import { themeColors } from "~/Constants"; import { getErrorString } from "~/Utility"; @@ -71,6 +78,8 @@ function Index() { const hideBanDialog = () => setBanDialogVisible(false); const [banLoading, setBanLoading] = useState(false); + const [promoteLoading, setPromoteLoading] = useState(false); + const { showDialog, showSnackBar } = useAlertContext(); const { currentUserId, currentTeamId } = useAuthContext(); @@ -246,6 +255,7 @@ function Index() { } onPress={async () => { try { + setPromoteLoading(true); await changeRole( currentTeamId, userId, @@ -258,8 +268,19 @@ function Index() { console.log(e); showDialog("Error", getErrorString(e)); } + setPromoteLoading(false); }} - title={userInfo.role === "player" ? "Promote" : "Demote"} + title={ + <> + {promoteLoading ? ( + + ) : ( + + {userInfo.role === "player" ? "Promote" : "Demote"} + + )} + + } /> } > + 1 ? "s" : ""}`} + onHide={() => { + setSnackbarVisible(false); + setUnbanCounter(0); + }} + /> prev + 1); + setSnackbarVisible(true); setUnbanLoading({ ...unbanLoading, [userId]: false }); } catch (e) { console.log(e); diff --git a/app/segments/(team)/invitelist.js b/app/segments/(team)/invitelist.js index bf0bc762..ca2f5c7e 100644 --- a/app/segments/(team)/invitelist.js +++ b/app/segments/(team)/invitelist.js @@ -11,6 +11,7 @@ import { import { Button, List } from "react-native-paper"; import { themeColors } from "~/Constants"; import { getErrorString } from "~/Utility"; +import DialogComponent from "~/components/dialog"; import ErrorComponent from "~/components/errorComponent"; import Loading from "~/components/loading"; import RefreshInvalidate from "~/components/refreshInvalidate"; @@ -45,6 +46,10 @@ export function Invitelist() { const [removeLoading, setRemoveLoading] = useState({}); const [inviteLoading, setInviteLoading] = useState(false); + const [removeCounter, setRemoveCounter] = useState(0); + + const [snackbarVisible, setSnackbarVisible] = useState(false); + const onInvite = async () => { if (inviteLoading) return; setInviteLoading(true); @@ -54,6 +59,7 @@ export function Invitelist() { } await addToInvitelist(currentTeamId, currentEmailInput); setCurrentEmailInput(""); + setCurrentEmailValid(false); await invalidateMultipleKeys(queryClient, invalidateKeys); setInviteLoading(false); }; @@ -75,6 +81,15 @@ export function Invitelist() { }} behavior={Platform.OS === "ios" ? "padding" : "height"} > + 1 ? "s" : ""}`} + onHide={() => { + setSnackbarVisible(false); + setRemoveCounter(0); + }} + /> } > @@ -108,6 +123,8 @@ export function Invitelist() { queryClient, invalidateKeys, ); + setRemoveCounter((prev) => prev + 1); + setSnackbarVisible(true); setRemoveLoading({ ...removeLoading, [inviteId]: false, diff --git a/app/segments/(team)/waitlist.js b/app/segments/(team)/waitlist.js index 4b7fa43f..45b18875 100644 --- a/app/segments/(team)/waitlist.js +++ b/app/segments/(team)/waitlist.js @@ -4,6 +4,7 @@ import { ScrollView, View } from "react-native"; import { ActivityIndicator, Button, List } from "react-native-paper"; import { themeColors } from "~/Constants"; import { getErrorString } from "~/Utility"; +import DialogComponent from "~/components/dialog"; import ErrorComponent from "~/components/errorComponent"; import Loading from "~/components/loading"; import RefreshInvalidate from "~/components/refreshInvalidate"; @@ -26,6 +27,11 @@ function Waitlist() { //this is a pretty blunt implementation... I'm using the same variable here because each entry will disappear after either buttons are pressed const [loading, setLoading] = useState({}); + const [snackbarCounter, setSnackbarCounter] = useState(0); + const [lastDecision, setLastDecision] = useState(""); + + const [snackbarVisible, setSnackbarVisible] = useState(false); + if (waitlistError) { return ; } @@ -40,6 +46,15 @@ function Waitlist() { } > + 1 ? "s" : ""}`} + onHide={() => { + setSnackbarVisible(false); + setSnackbarCounter(0); + }} + /> prev + 1); + } + setSnackbarVisible(true); setLoading({ ...loading, [userId]: false }); }} textColor={"green"} @@ -97,6 +119,13 @@ function Waitlist() { queryClient, invalidateKeys, ); + if (lastDecision !== "Rejected") { + setLastDecision("Rejected"); + setSnackbarCounter(1); + } else { + setSnackbarCounter((prev) => prev + 1); + } + setSnackbarVisible(true); setLoading({ ...loading, [userId]: false }); }} textColor={"red"} diff --git a/package.json b/package.json index 328ac8ee..b328ed6e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dependencies": { "@expo/ngrok": "^4.1.0", "@expo/webpack-config": "^19.0.0", + "@good-react-native/keyboard-avoider": "^1.1.4", "@gorhom/bottom-sheet": "^4", "@react-native-async-storage/async-storage": "1.23.1", "@tanstack/query-async-storage-persister": "^5.27.5", diff --git a/yarn.lock b/yarn.lock index 2df24088..ff3bf680 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1749,6 +1749,13 @@ resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.1.tgz#0b62c9f47f557a5b4adc073bb0a47542ce6af4c4" integrity sha512-jmEnr/pk0yVkA7mIlHNnxCi+wWzOFUg0WyIotgkKAb2u1J7fAeDBcVNSTjTihbAYNusCLQdW5s9IJ5qwnEufcQ== +"@good-react-native/keyboard-avoider@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@good-react-native/keyboard-avoider/-/keyboard-avoider-1.1.4.tgz#634a18d8634d100b2b4e1f419c4b56dc0ab831ab" + integrity sha512-Yfbr3b7pOdjdZW03cyHC5kVzFX7D1kPP2jr8yvT7hzI3zoCPuvwTjxzl80vjs3NWCGt1ZAPAbhEkG4oFzGaCSg== + dependencies: + react-native-uuid "^2.0.1" + "@gorhom/bottom-sheet@^4": version "4.6.3" resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.6.3.tgz#0e16999de7468efc6b730f680692f6d53f0abd8e" @@ -9360,6 +9367,11 @@ react-native-svg@15.2.0: css-select "^5.1.0" css-tree "^1.1.3" +react-native-uuid@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-native-uuid/-/react-native-uuid-2.0.2.tgz#3da192e342ef35ee95a7def676ab41c1256dfd66" + integrity sha512-5ypj/hV58P+6VREdjkW0EudSibsH3WdqDERoHKnD9syFWjF+NfRWWrJb2sa3LIwI5zpzMvUiabs+DX40WHpEMw== + react-native-web@~0.19.6: version "0.19.12" resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.19.12.tgz#30d1fd70bdff7886f43c0c2698629d830fade6bc"