From 7bf041be75df1be6aa39410ff4e88602ce9b6243 Mon Sep 17 00:00:00 2001
From: George Bell <47749730+GeorgeBellTMH@users.noreply.github.com>
Date: Tue, 23 May 2023 15:01:21 -0400
Subject: [PATCH] Added icons
---
amplify/backend/api/jcmobile/schema.graphql | 2 +
assets/20x20.png | Bin 0 -> 77 bytes
components/Header/Header.tsx | 11 +-
components/ProfileImage/JCImage.tsx | 89 ++
components/ProfileImage/useJCImage.ts | 49 +
components/ResourceViewer/ResourceImage.tsx | 3 +-
screens/Admin/AdminMenuScreen.tsx | 35 +-
src/API-customqueries.ts | 1288 ++++++++++---------
src/API.ts | 190 +++
src/graphql-custom/queries.ts | 14 +
src/graphql/mutations.ts | 63 +
src/graphql/queries.ts | 35 +
src/graphql/schema.json | 292 +++--
src/graphql/subscriptions.ts | 63 +
src/version.js | 2 +-
15 files changed, 1435 insertions(+), 701 deletions(-)
create mode 100644 assets/20x20.png
create mode 100644 components/ProfileImage/JCImage.tsx
create mode 100644 components/ProfileImage/useJCImage.ts
diff --git a/amplify/backend/api/jcmobile/schema.graphql b/amplify/backend/api/jcmobile/schema.graphql
index 2b2a859e..574f7d02 100644
--- a/amplify/backend/api/jcmobile/schema.graphql
+++ b/amplify/backend/api/jcmobile/schema.graphql
@@ -1415,6 +1415,7 @@ type Menu
name:String
action:String
params:String
+ icon:Image
readGroups:[UserGroupType]
subItems: [SubMenu] @connection(name:"subMenuMenu",keyField: "menuID",sortField:"order")
@@ -1434,6 +1435,7 @@ type SubMenu
menu:Menu @connection(name:"subMenuMenu",keyField:"menuID")
name:String
action:String
+ icon:Image
params:String
readGroups:[UserGroupType]
}
diff --git a/assets/20x20.png b/assets/20x20.png
new file mode 100644
index 0000000000000000000000000000000000000000..f5e95666f1f51df0823de9edce5e6447fc5978c2
GIT binary patch
literal 77
zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc0wmQNuC{?Vo-U3d6}OU86od@=v}8gpRtc~$
Ys9a+Zy>IoI4=B&z>FVdQ&MBb@04vH6{{R30
literal 0
HcmV?d00001
diff --git a/components/Header/Header.tsx b/components/Header/Header.tsx
index 96d44bf6..d6e4ef14 100644
--- a/components/Header/Header.tsx
+++ b/components/Header/Header.tsx
@@ -12,12 +12,13 @@ import {
StyleSheet,
Text,
TouchableOpacity,
- useWindowDimensions,
View,
+ useWindowDimensions,
} from "react-native"
import { ListMenusQuery } from "src/API-customqueries"
import SearchInactiveIcon from "../../assets/Facelift/svg/Search-2.svg"
import { Data } from "../../components/Data/Data"
+import JCImage, { JCImageQuality, JCImageStyle } from "../../components/ProfileImage/JCImage"
import { constants } from "../../src/constants"
import { JCCognitoUser } from "../../src/types"
import SearchBar from "../Forms/SearchBar/SearchBar"
@@ -278,6 +279,14 @@ export default function HeaderJC(props: Props) {
openScreen(subItem.action ?? "", subItem.params)
}}
>
+
+
+
{subItem.name}
diff --git a/components/ProfileImage/JCImage.tsx b/components/ProfileImage/JCImage.tsx
new file mode 100644
index 00000000..d6b4ad54
--- /dev/null
+++ b/components/ProfileImage/JCImage.tsx
@@ -0,0 +1,89 @@
+import React, { useEffect, useRef } from "react"
+import {
+ Animated,
+ Image,
+ ImageSourcePropType,
+ ImageStyle,
+ StyleSheet,
+ View,
+ ViewStyle,
+} from "react-native"
+import { ImageInput } from "src/API"
+import DefaultImage from "../../assets/20x20.png"
+import useJCImage from "./useJCImage"
+
+export enum JCImageQuality {
+ small = "small",
+ medium = "medium",
+ large = "large",
+}
+export enum JCImageStyle {
+ IconSmall = "IconSmall",
+}
+type JCImageType = "icon" | "resource"
+export type JCImageProps = {
+ containerStyle?: ViewStyle
+ imageStyle?: ImageStyle
+ style: JCImageStyle
+ quality: JCImageQuality
+ type: JCImageType
+ image: ImageInput | null | undefined
+ linkToProfile?: boolean
+ showNameInToolTip?: boolean
+}
+
+export const ProfileImageStyles = StyleSheet.create({
+ Bordered: {
+ borderColor: "#E4E1E1",
+ borderWidth: 0,
+ // for some reason, borderWidth:1 breaks the image spacing on Chrome browser randomly
+ // not sure what's going on here
+ },
+ ImageContainer: {
+ backgroundColor: "#fff",
+ },
+ IconSmall: {
+ height: 20,
+ width: 20,
+ },
+})
+export default function JCImage(props: JCImageProps) {
+ const { url, isLoading = true } = useJCImage(props)
+ const fadeAnim = useRef(new Animated.Value(0)).current
+ const fadeAnim2 = useRef(new Animated.Value(1)).current
+ const fade = () => {
+ Animated.timing(fadeAnim, {
+ toValue: 1,
+ duration: 1000,
+ useNativeDriver: true,
+ }).start()
+ Animated.timing(fadeAnim2, {
+ toValue: 0,
+ duration: 1000,
+ useNativeDriver: true,
+ }).start()
+ }
+ useEffect(() => {
+ if (url && !isLoading) fade()
+ }, [url, isLoading])
+ return (
+
+
+
+
+ {!isLoading && url ? (
+
+
+
+ ) : null}
+
+ )
+}
diff --git a/components/ProfileImage/useJCImage.ts b/components/ProfileImage/useJCImage.ts
new file mode 100644
index 00000000..3ba66736
--- /dev/null
+++ b/components/ProfileImage/useJCImage.ts
@@ -0,0 +1,49 @@
+import { Storage } from "aws-amplify"
+import { useEffect, useState } from "react"
+import { JCImageProps } from "./JCImage"
+
+export default function useJCImage(props: JCImageProps) {
+ const [url, setUrl] = useState("")
+ const [isLoading, setIsLoading] = useState(true)
+ useEffect(() => {
+ const loadImageFromStorage = async () => {
+ let imgUrl: string | null | undefined
+ switch (props.quality) {
+ case "large":
+ imgUrl = props.image?.filenameLarge
+ break
+ case "medium":
+ imgUrl = props.image?.filenameMedium
+ break
+ case "small":
+ imgUrl = props.image?.filenameSmall
+ break
+ default:
+ imgUrl = props.image?.filenameMedium
+ break
+ }
+ try {
+ setIsLoading(true)
+ if (imgUrl) {
+ // Storage.get() not throwing error when file does not exist
+ // Current implementation shows default image while loading
+ // Errored requests that don't throw an error will maintain loading state,
+ const pfImage = await Storage.get(imgUrl, {
+ level: "protected",
+ contentType: "image/png",
+ identityId: props.image?.userId ?? "",
+ })
+ setIsLoading(false)
+ setUrl(pfImage)
+ } else {
+ console.log("No Image URL Found.")
+ }
+ } catch (err) {
+ console.log({ err })
+ setUrl("")
+ }
+ }
+ if (props.image) loadImageFromStorage()
+ }, [props.quality, props.image])
+ return { url: url, isLoading }
+}
diff --git a/components/ResourceViewer/ResourceImage.tsx b/components/ResourceViewer/ResourceImage.tsx
index 4504b721..ed52f78a 100644
--- a/components/ResourceViewer/ResourceImage.tsx
+++ b/components/ResourceViewer/ResourceImage.tsx
@@ -10,6 +10,7 @@ interface Props {
fileName: string
currentImage: ImageInput | null | undefined
onUpdate(image: ImageInput): void
+ style?: ButtonTypes
}
interface State extends JCState {
uploading: boolean
@@ -46,7 +47,7 @@ class ResourceImage extends JCComponent {
) : (
<>
{
null
}}
diff --git a/screens/Admin/AdminMenuScreen.tsx b/screens/Admin/AdminMenuScreen.tsx
index 745fc888..e98e4d6c 100644
--- a/screens/Admin/AdminMenuScreen.tsx
+++ b/screens/Admin/AdminMenuScreen.tsx
@@ -9,7 +9,9 @@ import { Data } from "../../components/Data/Data"
import JCButton, { ButtonTypes } from "../../components/Forms/JCButton"
import JCModal from "../../components/Forms/JCModal"
import Header from "../../components/Header/Header"
-import { ListSubMenusQuery, UserGroupType } from "../../src/API"
+import JCImage, { JCImageQuality, JCImageStyle } from "../../components/ProfileImage/JCImage"
+import ResourceImage from "../../components/ResourceViewer/ResourceImage"
+import { ImageInput, ListSubMenusQuery, UserGroupType } from "../../src/API"
import { UserContext } from "../HomeScreen/UserContext"
interface Props {
navigation: StackNavigationProp
@@ -31,6 +33,7 @@ export default function AdminScreen(props: Props) {
const [menuName, setMenuName] = useState()
const [menuProps, setMenuProps] = useState()
const [subMenuName, setSubMenuName] = useState()
+ const [subMenuImage, setSubMenuImage] = useState()
const [menuAction, setMenuAction] = useState()
const [subMenuAction, setSubMenuAction] = useState()
const [subMenuProps, setSubMenuProps] = useState()
@@ -103,6 +106,7 @@ export default function AdminScreen(props: Props) {
const z = await Data.updateSubMenu({
id: showEditSubMenuItem,
name: subMenuName,
+ icon: subMenuImage,
action: subMenuAction,
params: subMenuProps,
readGroups: groupData,
@@ -112,6 +116,7 @@ export default function AdminScreen(props: Props) {
setSubMenuAction("")
setSubMenuProps("")
setGroupData([])
+ setSubMenuImage({})
await setInitialData()
closeAddSubMenuItem()
}
@@ -127,6 +132,7 @@ export default function AdminScreen(props: Props) {
params: subMenuProps,
readGroups: groupData,
menuID: showAddSubMenuItem,
+ icon: subMenuImage,
order: menus.filter((f) => f.id == showAddSubMenuItem)[0].subItems?.items.length,
})
console.log(z)
@@ -134,6 +140,7 @@ export default function AdminScreen(props: Props) {
setSubMenuAction("")
setSubMenuProps("")
setGroupData([])
+ setSubMenuImage({})
await setInitialData()
closeAddSubMenuItem()
} catch (e) {
@@ -287,6 +294,14 @@ export default function AdminScreen(props: Props) {
value={subMenuProps}
style={styles.adminCRMModalInviteEmail}
>
+ {
+ setSubMenuImage(image)
+ }}
+ style={ButtonTypes.AdminOutline}
+ fileName={"menus/upload/icon-test-"}
+ currentImage={subMenuImage}
+ >
Visible to:
{groupData
? groupData.map((item: any, index: number) => {
@@ -370,6 +385,7 @@ export default function AdminScreen(props: Props) {
setShowAddSubMenuItem(null)
setShowEditSubMenuItem(null)
setSubMenuName("")
+ setSubMenuImage({})
setSubMenuAction("")
setSubMenuProps("")
setGroupData([])
@@ -386,6 +402,7 @@ export default function AdminScreen(props: Props) {
const editSubMenuItem = (item: any) => {
setShowEditSubMenuItem(item.id)
setSubMenuName(item.name)
+ setSubMenuImage(item.icon)
setSubMenuAction(item.action)
setSubMenuProps(item.params)
setGroupData(item.readGroups)
@@ -525,6 +542,14 @@ export default function AdminScreen(props: Props) {
+
+
+
{item.name}
+
+
+
{item2.name}
| null
- or?: Array | null
- not?: ModelMenuFilterInput | null
-}
-
-export type ModelIDFilterInput = {
- ne?: string | null
- eq?: string | null
- le?: string | null
- lt?: string | null
- ge?: string | null
- gt?: string | null
- contains?: string | null
- notContains?: string | null
- between?: Array | null
- beginsWith?: string | null
-}
-
-export type ModelIntFilterInput = {
- ne?: number | null
- eq?: number | null
- le?: number | null
- lt?: number | null
- ge?: number | null
- gt?: number | null
- between?: Array | null
-}
-
-export type ModelStringFilterInput = {
- ne?: string | null
- eq?: string | null
- le?: string | null
- lt?: string | null
- ge?: string | null
- gt?: string | null
- contains?: string | null
- notContains?: string | null
- between?: Array | null
- beginsWith?: string | null
-}
-
-export type ModelUserGroupTypeListFilterInput = {
- eq?: Array | null
- ne?: Array | null
- contains?: UserGroupType | null
- notContains?: UserGroupType | null
-}
-
-export enum UserGroupType {
- verifiedUsers = "verifiedUsers",
- admin = "admin",
- courseAdmin = "courseAdmin",
- courseCoach = "courseCoach",
- courseUser = "courseUser",
- friends = "friends",
- partners = "partners",
- subscriptionPartners = "subscriptionPartners",
- subscriptionkyearlyyears = "subscriptionkyearlyyears",
- subscriptionkykids = "subscriptionkykids",
- subscriptionkyyouth = "subscriptionkyyouth",
- subscriptionValid = "subscriptionValid",
- userpool = "userpool",
- legacyUserGroup1 = "legacyUserGroup1",
- productMarkBaker = "productMarkBaker",
- courseGroup1 = "courseGroup1",
- courseGroup2 = "courseGroup2",
- courseGroup3 = "courseGroup3",
- courseGroup4 = "courseGroup4",
- courseGroup5 = "courseGroup5",
- courseGroup6 = "courseGroup6",
- courseGroup7 = "courseGroup7",
- courseGroup8 = "courseGroup8",
- courseGroup9 = "courseGroup9",
-}
-
-export type ModelMenuConnection = {
- __typename: "ModelMenuConnection"
- items: Array