From 417c7962d74f714e53ed051ca09cf343cb96a7ce Mon Sep 17 00:00:00 2001 From: dev-rathore Date: Tue, 12 Nov 2024 13:36:27 +0530 Subject: [PATCH 01/12] commenting-leaflet-changes-for-web --- app/modal.web.tsx | 93 ++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/app/modal.web.tsx b/app/modal.web.tsx index 1b453682..37cf74a0 100644 --- a/app/modal.web.tsx +++ b/app/modal.web.tsx @@ -16,15 +16,15 @@ import { RadioButton, Modal, } from "react-native-paper"; -import { - MapContainer, - TileLayer, - Marker, - Popup, - useMapEvents, -} from "react-leaflet"; -import "leaflet/dist/leaflet.css"; -import L from "leaflet"; +// import { +// MapContainer, +// TileLayer, +// Marker, +// Popup, +// useMapEvents, +// } from "react-leaflet"; +// import L from "leaflet"; +// import "leaflet/dist/leaflet.css"; import stylesFn from "@/styles/modal/UploadModal.styles"; import { useTheme } from "@react-navigation/native"; import { addDoc, collection } from "firebase/firestore"; @@ -38,16 +38,16 @@ import { router } from "expo-router"; import BackButton from "@/components/ui/back-button/BackButton"; import { Ionicons } from "@expo/vector-icons"; -const customIcon = new L.Icon({ - iconUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png", - iconRetinaUrl: - "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png", - shadowUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png", - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - shadowSize: [41, 41], -}); +// const customIcon = new L.Icon({ +// iconUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png", +// iconRetinaUrl: +// "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png", +// shadowUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png", +// iconSize: [25, 41], +// iconAnchor: [12, 41], +// popupAnchor: [1, -34], +// shadowSize: [41, 41], +// }); const CreateCollaborationScreen = () => { const [collaborationName, setCollaborationName] = useState(""); @@ -137,15 +137,15 @@ const CreateCollaborationScreen = () => { } }; - const MapClickHandler = () => { - useMapEvents({ - click(e: any) { - const { lat, lng } = e.latlng; - setMapRegion((prev) => ({ ...prev, latitude: lat, longitude: lng })); - }, - }); - return null; - }; + // const MapClickHandler = () => { + // useMapEvents({ + // click(e: any) { + // const { lat, lng } = e.latlng; + // setMapRegion((prev) => ({ ...prev, latitude: lat, longitude: lng })); + // }, + // }); + // return null; + // }; if (screen === 1) { return ( @@ -376,24 +376,25 @@ const CreateCollaborationScreen = () => { {location === "Physical" && ( - - - - Location - - - + null + // + // + // + // Location + // + // + // )} */} - - - {props.collaborationDetail.appliedCount} Applied - - - {props.collaborationDetail.brandViewed} Reviewed - - - {props.collaborationDetail.location.type === "Remote" - ? "Remote" - : props.collaborationDetail.location.name} - - - - + { + activeTab === "Overview" && ( + <> + {/* Collaboration Details */} + + + + + {props.collaborationDetail.name} + + + {props.collaborationDetail.brandName} + + + {props.collaborationDetail.description} + + {/* + + */} + + + {props.collaborationDetail.appliedCount} Applied + + + {props.collaborationDetail.brandViewed} Reviewed + + + {props.collaborationDetail.location.type === "Remote" + ? "Remote" + : props.collaborationDetail.location.name} + + + + - {/* Ad Description Section */} - - {/* */} - - - Ad Description - - - - - {" "} - {props.collaborationDetail.description} - - - + {/* Ad Description Section */} + + {/* */} + + + Ad Description + + + + + {" "} + {props.collaborationDetail.description} + + + - {/* About Brand Section */} - - {/* */} - - - About Brand - - - - - {props.collaborationDetail.description} - - - + {/* About Brand Section */} + + {/* */} + + + About Brand + + + + + {props.collaborationDetail.description} + + + - {/* Platform Section */} - - {/* */} - - - Platform - - - - Instagram - - + {/* Platform Section */} + + {/* */} + + + Platform + + + + Instagram + + - {/* Payment Details Section */} - - {/* */} - - - Payment Details - - - - - Cost: {props.collaborationDetail.budget.min} - - - Payment Verified: True - - - + {/* Payment Details Section */} + + {/* */} + + + Payment Details + + + + + Cost: {props.collaborationDetail.budget.min} + + + Payment Verified: True + + + + + ) + } + { + // Application Tab + activeTab === "Application" && ( + + ) + } + { + activeTab === "Invitation" && ( + + ) + } - )} - { - // Application Tab - activeTab === "Application" && ( - - ) - } - {activeTab === "Invitation" && ( - - )} + { - return ( - - Create a Collaboration - - ); -}; - -export default CreateCollaboration; diff --git a/components/drawer-layout/BrandItem.tsx b/components/drawer-layout/BrandItem.tsx index a14673b7..2da90559 100644 --- a/components/drawer-layout/BrandItem.tsx +++ b/components/drawer-layout/BrandItem.tsx @@ -47,9 +47,11 @@ const BrandItem: React.FC = ({ showImage && ( void; +} + +const Map: React.FC = ({ + location, + onLocationChange, +}) => { + const handleOnMapClick = useCallback((event: MapMouseEvent) => { + event.map?.setCenter(event.detail.latLng as any); + + onLocationChange({ + latitude: event.detail.latLng?.lat as number, + longitude: event.detail.latLng?.lng as number, + }); + }, []); + + return ( + + { + location.latitude && location.longitude && ( + + + + ) + } + + ); +}; + +export default Map; diff --git a/components/menu/index.tsx b/components/menu/index.tsx index afe870a3..ca51c639 100644 --- a/components/menu/index.tsx +++ b/components/menu/index.tsx @@ -34,15 +34,20 @@ const Menu = () => { return ( @@ -96,9 +101,11 @@ const Menu = () => { > diff --git a/constants/Colors.ts b/constants/Colors.ts index 52e58a0e..7a8c1472 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -12,6 +12,7 @@ export default (theme: Theme) => ({ tint: tintColorDark, tabIconDefault: "#ccc", tabIconSelected: tintColorDark, + inputBackground: "#1b1b1b", } : { text: "#000", @@ -19,15 +20,30 @@ export default (theme: Theme) => ({ tint: tintColorLight, tabIconDefault: "#ccc", tabIconSelected: tintColorLight, + inputBackground: "#fff", }), aliceBlue: "#E9F1F7", + amber: "#FFBF00", + unicornSilver: "#e8e8e8", + eerieBlack: "#1b1b1b", + whiteSmoke: "#f5f5f5", + success: "#d4edda", + successForeground: "#28a745", + pink: "#f8d7da", + pinkForeground: "#dc3545", backdrop: "rgba(0, 0, 0, 0.5)", black: "#000", lightgray: "lightgray", - notificationDot: "red", + modalBackground: "rgba(0, 0, 0, 0.5)", + onSurface: "#1976d2", + orange: "#F64740", platinum: "#DBDBDB", primary: "#1976d2", + red: "red", + notificationDot: "red", gray100: "#555", - white: "#ffffff", + surface: "#ffffff", + surfaceVariant: "#ffffff", transparent: "transparent", + white: "#ffffff", }); diff --git a/constants/Themes/Colors.ts b/constants/Themes/Colors.ts deleted file mode 100644 index 90c3e5c5..00000000 --- a/constants/Themes/Colors.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Theme } from "@react-navigation/native"; - -const tintColorLight = "#ff6d2d"; -const tintColorDark = "#fff"; - -export default (theme: Theme) => ({ - ...theme.colors, - ...(theme.dark - ? { - text: "#fff", - background: "#000", - tint: tintColorDark, - tabIconDefault: "#ccc", - tabIconSelected: tintColorDark, - inputBackground: "#1b1b1b", - } - : { - text: "#000", - background: "#fff", - tint: tintColorLight, - tabIconDefault: "#ccc", - tabIconSelected: tintColorLight, - inputBackground: "#fff", - }), - aliceBlue: "#E9F1F7", - amber: "#FFBF00", - unicornSilver: "#e8e8e8", - eerieBlack: "#1b1b1b", - whiteSmoke: "#f5f5f5", - success: "#d4edda", - successForeground: "#28a745", - pink: "#f8d7da", - pinkForeground: "#dc3545", - backdrop: "rgba(0, 0, 0, 0.5)", - black: "#000", - lightgray: "lightgray", - modalBackground: "rgba(0, 0, 0, 0.5)", - onSurface: "#1976d2", - orange: "#F64740", - platinum: "#DBDBDB", - primary: "#1976d2", - red: "red", - gray100: "#555", - surface: "#ffffff", - surfaceVariant: "#ffffff", - white: "#ffffff", -}); diff --git a/constants/Themes/Theme.ts b/constants/Themes/Theme.ts index dea7846b..f6fefbae 100644 --- a/constants/Themes/Theme.ts +++ b/constants/Themes/Theme.ts @@ -1,6 +1,6 @@ import { DefaultTheme as PaperDefaultTheme } from "react-native-paper"; import { Theme } from "@react-navigation/native"; -import Colors from "./Colors"; +import Colors from "../Colors"; const CustomPaperTheme = (theme: Theme) => ({ ...PaperDefaultTheme, diff --git a/contexts/brand-context.provider.tsx b/contexts/brand-context.provider.tsx index 9940c7da..942ca61b 100644 --- a/contexts/brand-context.provider.tsx +++ b/contexts/brand-context.provider.tsx @@ -63,7 +63,11 @@ export const BrandContextProvider: React.FC = ({ }); }); - return () => unsubscribe(); + return () => { + unsubscribe(); + setSelectedBrand(undefined); + setBrands([]); + }; }, [manager?.id]); return ( diff --git a/layouts/app-layout/index.tsx b/layouts/app-layout/index.tsx index 117b03fe..6a9ecc50 100644 --- a/layouts/app-layout/index.tsx +++ b/layouts/app-layout/index.tsx @@ -2,10 +2,10 @@ import { PropsWithChildren, useMemo } from "react"; import { Platform, SafeAreaView, StatusBar, StyleSheet } from "react-native"; import { StatusBar as ExpoStatusBar } from "expo-status-bar"; -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { useTheme } from "@react-navigation/native"; -interface AppLayoutProps extends PropsWithChildren> {} +interface AppLayoutProps extends PropsWithChildren> { } const AppLayout: React.FC = ({ children }) => { const theme = useTheme(); diff --git a/package-lock.json b/package-lock.json index b970598d..2202cd28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.0.2", "@stream-io/flat-list-mvcp": "^0.10.3", + "@vis.gl/react-google-maps": "^1.4.0", "date-fns": "^4.1.0", "expo": "~51.0.21", "expo-av": "^14.0.7", @@ -35,16 +36,15 @@ "expo-image-manipulator": "~12.0.5", "expo-image-picker": "^15.0.7", "expo-linking": "~6.3.1", + "expo-location": "~17.0.1", "expo-router": "~3.5.18", "expo-secure-store": "^13.0.2", "expo-splash-screen": "~0.27.5", "expo-status-bar": "~1.12.1", "expo-system-ui": "~3.0.7", "expo-web-browser": "~13.0.3", - "leaflet": "^1.9.4", "react": "18.2.0", "react-dom": "18.2.0", - "react-leaflet": "^4.2.1", "react-native": "0.74.3", "react-native-autocomplete-dropdown": "^3.0.2", "react-native-autocomplete-input": "^5.4.0", @@ -6445,17 +6445,6 @@ "react": "^16.8 || ^17.0 || ^18.0" } }, - "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, "node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", @@ -10035,6 +10024,12 @@ "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", "license": "MIT" }, + "node_modules/@types/google.maps": { + "version": "3.58.1", + "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz", + "integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==", + "license": "MIT" + }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -10279,6 +10274,20 @@ "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" } }, + "node_modules/@vis.gl/react-google-maps": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vis.gl/react-google-maps/-/react-google-maps-1.4.0.tgz", + "integrity": "sha512-M2pW1NjLGlT/HAMqtd3vWPfrlPh9wgcxVlnSmwCtmEJYzNV9ihiUz1awp7LHzsDoJ2XV0DuD4bwmnElKbxt9Ug==", + "license": "MIT", + "dependencies": { + "@types/google.maps": "^3.54.10", + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@web3-storage/multipart-parser": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz", @@ -14580,6 +14589,15 @@ "invariant": "^2.2.4" } }, + "node_modules/expo-location": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/expo-location/-/expo-location-17.0.1.tgz", + "integrity": "sha512-m+OzotzlAXO3ZZ1uqW5GC25nXW868zN+ROyBA1V4VF6jGay1ZEs4URPglCVUDzZby2F5wt24cMzqDKw2IX6nRw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-manifests": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-0.14.3.tgz", @@ -19833,12 +19851,6 @@ "node": ">= 0.6.3" } }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -22584,20 +22596,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/react-leaflet": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", - "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", - "license": "Hippocratic-2.1", - "dependencies": { - "@react-leaflet/core": "^2.1.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, "node_modules/react-native": { "version": "0.74.3", "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.74.3.tgz", diff --git a/package.json b/package.json index d93d1594..04421b2f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.0.2", "@stream-io/flat-list-mvcp": "^0.10.3", + "@vis.gl/react-google-maps": "^1.4.0", "date-fns": "^4.1.0", "expo": "~51.0.21", "expo-av": "^14.0.7", @@ -42,16 +43,15 @@ "expo-image-manipulator": "~12.0.5", "expo-image-picker": "^15.0.7", "expo-linking": "~6.3.1", + "expo-location": "~17.0.1", "expo-router": "~3.5.18", "expo-secure-store": "^13.0.2", "expo-splash-screen": "~0.27.5", "expo-status-bar": "~1.12.1", "expo-system-ui": "~3.0.7", "expo-web-browser": "~13.0.3", - "leaflet": "^1.9.4", "react": "18.2.0", "react-dom": "18.2.0", - "react-leaflet": "^4.2.1", "react-native": "0.74.3", "react-native-autocomplete-dropdown": "^3.0.2", "react-native-autocomplete-input": "^5.4.0", diff --git a/package.web.json b/package.web.json index 185ee158..7ade4378 100644 --- a/package.web.json +++ b/package.web.json @@ -31,6 +31,7 @@ "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.0.2", "@stream-io/flat-list-mvcp": "^0.10.3", + "@vis.gl/react-google-maps": "^1.4.0", "date-fns": "^4.1.0", "expo": "~51.0.21", "expo-av": "^14.0.7", @@ -42,6 +43,7 @@ "expo-image-manipulator": "~12.0.5", "expo-image-picker": "^15.0.7", "expo-linking": "~6.3.1", + "expo-location": "~17.0.1", "expo-router": "~3.5.18", "expo-secure-store": "^13.0.2", "expo-splash-screen": "~0.27.5", @@ -65,9 +67,7 @@ "react-native-swiper": "^1.6.0", "react-native-toast-message": "^2.2.1", "react-native-video": "^6.7.0", - "react-native-web": "~0.19.10", - "leaflet": "^1.9.4", - "react-leaflet": "^4.2.1" + "react-native-web": "~0.19.10" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -82,4 +82,4 @@ "typescript": "~5.3.3" }, "private": true -} +} \ No newline at end of file diff --git a/styles/CollaborationDetails.styles.tsx b/styles/CollaborationDetails.styles.tsx index d3004d1c..39c813c3 100644 --- a/styles/CollaborationDetails.styles.tsx +++ b/styles/CollaborationDetails.styles.tsx @@ -6,6 +6,7 @@ export const stylesFn = (theme: Theme) => StyleSheet.create({ scrollContainer: { padding: 16, + flex: 1, }, profileCard: { alignItems: "center", diff --git a/styles/forget-password.styles.tsx b/styles/forget-password.styles.tsx index cd56fb83..128a09ce 100644 --- a/styles/forget-password.styles.tsx +++ b/styles/forget-password.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/styles/login.styles.tsx b/styles/login.styles.tsx index 11971f6a..fb51a3d4 100644 --- a/styles/login.styles.tsx +++ b/styles/login.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/styles/onboarding/brand.styles.tsx b/styles/onboarding/brand.styles.tsx index e4500a78..256e4071 100644 --- a/styles/onboarding/brand.styles.tsx +++ b/styles/onboarding/brand.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; @@ -26,6 +26,7 @@ const fnStyles = (theme: Theme) => autocompleteContainer: { marginBottom: 20, zIndex: 1, + backgroundColor: Colors(theme).inputBackground, }, autocompleteInputContainer: { borderWidth: 1, diff --git a/styles/onboarding/get-started.styles.tsx b/styles/onboarding/get-started.styles.tsx index 92318fb7..ddc1a27f 100644 --- a/styles/onboarding/get-started.styles.tsx +++ b/styles/onboarding/get-started.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/styles/onboarding/preference.styles.tsx b/styles/onboarding/preference.styles.tsx index e609bd74..901966a6 100644 --- a/styles/onboarding/preference.styles.tsx +++ b/styles/onboarding/preference.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/styles/signup.styles.tsx b/styles/signup.styles.tsx index 06fcd3ba..d0231f80 100644 --- a/styles/signup.styles.tsx +++ b/styles/signup.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/styles/tab1.styles.tsx b/styles/tab1.styles.tsx index b0b6e532..8bec3100 100644 --- a/styles/tab1.styles.tsx +++ b/styles/tab1.styles.tsx @@ -1,4 +1,4 @@ -import Colors from "@/constants/Themes/Colors"; +import Colors from "@/constants/Colors"; import { Theme } from "@react-navigation/native"; import { StyleSheet } from "react-native"; diff --git a/utils/url.ts b/utils/url.ts new file mode 100644 index 00000000..929d1d6b --- /dev/null +++ b/utils/url.ts @@ -0,0 +1,11 @@ +export const queryParams = ( + params: Partial> +) => { + let values: string[] = []; + + Object.entries(params).map(([key, value]) => { + values.push(`${key}=${value}`); + }); + + return values.length === 0 ? "" : `?${values.join("&")}`; +}; From f5fa778a1ae1ec4bc47b53c4cc31172226d59522 Mon Sep 17 00:00:00 2001 From: Rahul Sinha Date: Thu, 14 Nov 2024 21:40:40 +0530 Subject: [PATCH 05/12] Update deploy-action.yaml (#29) --- .github/workflows/deploy-action.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-action.yaml b/.github/workflows/deploy-action.yaml index 671cbc26..96314cf0 100644 --- a/.github/workflows/deploy-action.yaml +++ b/.github/workflows/deploy-action.yaml @@ -25,8 +25,10 @@ jobs: - name: Load Config JS env: FIREBASE_CONFIG_BASE64: ${{ secrets.TRENDLY_FIREBASE_CONFIG }} + ENV_LOCAL_BASE64: ${{ secrets.ENV_LOCAL_FILE }} run: | echo $FIREBASE_CONFIG_BASE64 | base64 -d > firebase-config.js + echo $ENV_LOCAL_BASE64 | base64 -d > .env.local - run: npm run build - name: serverless deploy uses: serverless/github-action@v3.2 @@ -36,4 +38,4 @@ jobs: # SERVERLESS_ACCESS_KEY: ${{ secrets.SERVERLESS_ACCESS_KEY }} # or if using AWS credentials directly AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} \ No newline at end of file + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} From 815cb9311d34a26b29509ebca95b9600ea24bf35 Mon Sep 17 00:00:00 2001 From: dev-rathore Date: Thu, 14 Nov 2024 23:05:02 +0530 Subject: [PATCH 06/12] new brand fix --- app/(onboarding)/onboarding-get-started.tsx | 25 ++++++++++++++++----- app/(onboarding)/onboarding-your-brand.tsx | 11 --------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/(onboarding)/onboarding-get-started.tsx b/app/(onboarding)/onboarding-get-started.tsx index 8f9765d4..6ac56f6a 100644 --- a/app/(onboarding)/onboarding-get-started.tsx +++ b/app/(onboarding)/onboarding-get-started.tsx @@ -2,15 +2,16 @@ import Colors from "@/constants/Colors"; import { useAuthContext } from "@/contexts"; import AppLayout from "@/layouts/app-layout"; import fnStyles from "@/styles/onboarding/get-started.styles"; -import { DUMMY_MANAGER_CREDENTIALS } from "@/constants/Manager"; import { useTheme } from "@react-navigation/native"; import React, { useState } from "react"; -import { View, Text, StyleSheet, Button, TouchableOpacity } from "react-native"; -import { Menu, Provider } from "react-native-paper"; +import { View, Text, Button, TouchableOpacity } from "react-native"; +import { Menu } from "react-native-paper"; import { AuthApp } from "@/utils/auth"; import { router, useLocalSearchParams } from "expo-router"; -import { doc, setDoc } from "firebase/firestore"; +import { doc, getDoc, setDoc } from "firebase/firestore"; import { FirestoreDB } from "@/utils/firestore"; +import { useBrandContext } from "@/contexts/brand-context.provider"; +import { Brand } from "@/types/Brand"; const GetStartedScreen = () => { const [hearAboutUs, setHearAboutUs] = useState(""); @@ -39,13 +40,17 @@ const GetStartedScreen = () => { const params = useLocalSearchParams(); - const handleSubmit = () => { + const { + setSelectedBrand, + } = useBrandContext(); + + const handleSubmit = async () => { try { const { brandId } = params; if (brandId) { //@ts-ignore const brandRef = doc(FirestoreDB, "brands", brandId); - setDoc( + await setDoc( brandRef, { survey: { @@ -56,6 +61,14 @@ const GetStartedScreen = () => { }, { merge: true } ); + + const brandData = await getDoc(brandRef); + + setSelectedBrand({ + ...(brandData.data() as Brand), + id: brandRef.id, + }); + router.push("/(main)/explore-influencers"); } } catch (error) { diff --git a/app/(onboarding)/onboarding-your-brand.tsx b/app/(onboarding)/onboarding-your-brand.tsx index 03cb5ebe..0f457285 100644 --- a/app/(onboarding)/onboarding-your-brand.tsx +++ b/app/(onboarding)/onboarding-your-brand.tsx @@ -19,8 +19,6 @@ import { addDoc, collection, doc, setDoc } from "firebase/firestore"; import { FirestoreDB } from "@/utils/firestore"; import Toast from "react-native-toast-message"; import Toaster from "@/shared-uis/components/toaster/Toaster"; -import { useBrandContext } from "@/contexts/brand-context.provider"; -import { Brand } from "@/types/Brand"; import Colors from "@/constants/Colors"; const OnboardingScreen = () => { @@ -38,10 +36,6 @@ const OnboardingScreen = () => { firstBrand, } = useLocalSearchParams(); - const { - setSelectedBrand, - } = useBrandContext(); - const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, @@ -106,11 +100,6 @@ const OnboardingScreen = () => { role, }); - setSelectedBrand({ - ...(brandData as Brand), - id: docRef.id, - }); - router.navigate({ pathname: "/(onboarding)/onboarding-brand-preference", params: { brandId: docRef.id }, From fd62005ed67a812d3ef8eafba83aacf3748bac31 Mon Sep 17 00:00:00 2001 From: Devender Singh Rathore <59788555+dev-rathore@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:04:03 +0530 Subject: [PATCH 07/12] Carousel for web (#30) * carousel for web changes * crash scenario * drawer ui improvement --- components/InfluencerCard.tsx | 124 ++++-------------- .../drawer-layout/DrawerMenuContent.tsx | 106 ++++++++------- components/ui/carousel/carousel.tsx | 87 ++++++++++++ components/ui/carousel/carousel.web.tsx | 59 +++++++++ components/ui/carousel/render-media-item.tsx | 91 +++++++++++++ styles/InfluencerCard.styles.tsx | 2 +- 6 files changed, 315 insertions(+), 154 deletions(-) create mode 100644 components/ui/carousel/carousel.tsx create mode 100644 components/ui/carousel/carousel.web.tsx create mode 100644 components/ui/carousel/render-media-item.tsx diff --git a/components/InfluencerCard.tsx b/components/InfluencerCard.tsx index 1a27deca..1c5a439b 100644 --- a/components/InfluencerCard.tsx +++ b/components/InfluencerCard.tsx @@ -1,25 +1,20 @@ import { router } from "expo-router"; -import React, { useState, useRef } from "react"; +import React, { useEffect, useState } from "react"; import { View, Text, - Image, StyleSheet, TouchableOpacity, Dimensions, Modal, - Platform, + ActivityIndicator, } from "react-native"; import { Card, Avatar, IconButton, Chip } from "react-native-paper"; -import Carousel from "react-native-reanimated-carousel"; -import { ResizeMode, Video } from "expo-av"; import { stylesFn } from "@/styles/InfluencerCard.styles"; import { useTheme } from "@react-navigation/native"; import { PinchGestureHandler, PinchGestureHandlerGestureEvent, - TapGestureHandler, - State, } from "react-native-gesture-handler"; import Animated, { useAnimatedGestureHandler, @@ -29,7 +24,7 @@ import Animated, { } from "react-native-reanimated"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import Colors from "@/constants/Colors"; -import { influencers } from "@/constants/Influencers"; +import CarouselNative from "./ui/carousel/carousel"; const { width } = Dimensions.get("window"); @@ -57,19 +52,15 @@ interface InfluencerCardPropsType { const InfluencerCard = (props: InfluencerCardPropsType) => { const [bioExpanded, setBioExpanded] = useState(false); - const [currentIndex, setCurrentIndex] = useState(0); - const [muted, setMuted] = useState(true); - const [isPlaying, setIsPlaying] = useState(true); - const [isZoomed, setIsZoomed] = useState(false); const [selectedImage, setSelectedImage] = useState(null); - const [isSwiping, setIsSwiping] = useState(false); + const [isZoomed, setIsZoomed] = useState(false); + const [loading, setLoading] = useState(true); // Animation values for zoom const scale = useSharedValue(1); const focalX = useSharedValue(0); const focalY = useSharedValue(0); - const videoRefs = useRef<{ [key: number]: any }>({}); const influencer = props.influencer; const theme = useTheme(); const styles = stylesFn(theme); @@ -102,69 +93,24 @@ const InfluencerCard = (props: InfluencerCardPropsType) => { }; }); - const handleIndexChange = (index: number) => { - setCurrentIndex(index); - setIsSwiping(true); - // Reset swiping state after a short delay - setTimeout(() => setIsSwiping(false), 150); - Object.values(videoRefs.current).forEach((videoRef) => { - if (videoRef && videoRef.seek) { - videoRef.seek(0); - setIsPlaying(false); - } - }); - }; + const onImagePress = (data: any) => { + setSelectedImage(data); // TODO: data -> uri + setIsZoomed(true); + } - const handleImagePress = (uri: string) => { - if (!isSwiping) { - setSelectedImage(uri); - setIsZoomed(true); - } - }; + useEffect(() => { + const timer = setTimeout(() => { + setLoading(false); + }, 1000); - const renderMediaItem = ({ item, index }: any) => { - if (item.type === "image") { - return ( - { - if (nativeEvent.state === State.ACTIVE) { - handleImagePress(item.uri); - } - }} - > - - - - - ); - } else { - return ( - - - - - {influencer.media.map((_: any, index: any) => ( - - ))} - - + diff --git a/components/drawer-layout/DrawerMenuContent.tsx b/components/drawer-layout/DrawerMenuContent.tsx index ed77938c..f35956ee 100644 --- a/components/drawer-layout/DrawerMenuContent.tsx +++ b/components/drawer-layout/DrawerMenuContent.tsx @@ -1,5 +1,4 @@ import { Text, View } from "@/components/theme/Themed"; -import { DrawerContentScrollView } from "@react-navigation/drawer"; import { APP_NAME } from "@/constants/App"; import DrawerMenuItem from "./DrawerMenuItem"; import { useBreakpoints } from "@/hooks"; @@ -9,7 +8,7 @@ import { useNavigation, useRouter } from "expo-router"; import { useBrandContext } from "@/contexts/brand-context.provider"; import { Brand } from "@/types/Brand"; import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { Platform } from "react-native"; +import { Platform, ScrollView } from "react-native"; import BrandActionItem from "./BrandActionItem"; import Colors from "@/constants/Colors"; import { useEffect, useState } from "react"; @@ -81,64 +80,63 @@ const DrawerMenuContent: React.FC = () => { - - + - - - {APP_NAME} - - - - { - !xl && ( - - ) - } - {xl ? DRAWER_MENU_CONTENT_ITEMS.map((tab, index) => ( - - )) : filteredBrands.map((brand) => ( - handleBrandChange(brand)} - showImage={true} - title={brand.name} - /> - ))} - + {APP_NAME} + + { + !xl && ( + + ) + } + + + + {xl ? DRAWER_MENU_CONTENT_ITEMS.map((tab, index) => ( + + )) : filteredBrands.map((brand) => ( + handleBrandChange(brand)} + showImage={true} + title={brand.name} + /> + ))} - + void; +} + +const CarouselNative: React.FC = ({ + data, + onImagePress, +}) => { + const [currentIndex, setCurrentIndex] = useState(0); + const [isPlaying, setIsPlaying] = useState(true); + const [isSwiping, setIsSwiping] = useState(false); + + const videoRefs = useRef<{ [key: number]: any }>({}); + + const theme = useTheme(); + const styles = stylesFn(theme); + + const handleIndexChange = (index: number) => { + setCurrentIndex(index); + setIsSwiping(true); + // Reset swiping state after a short delay + setTimeout(() => setIsSwiping(false), 150); + Object.values(videoRefs.current).forEach((videoRef) => { + if (videoRef && videoRef.seek) { + videoRef.seek(0); + setIsPlaying(false); + } + }); + }; + + const handleImagePress = (uri: string) => { + if (!isSwiping) { + if (onImagePress) { + onImagePress(uri); + } + } + }; + + return ( + + ( + + )} + onSnapToItem={handleIndexChange} + style={{ + padding: 10, + }} + /> + + + {data.map((_: any, index: any) => ( + + ))} + + + ); +}; + +export default CarouselNative; diff --git a/components/ui/carousel/carousel.web.tsx b/components/ui/carousel/carousel.web.tsx new file mode 100644 index 00000000..04690fb1 --- /dev/null +++ b/components/ui/carousel/carousel.web.tsx @@ -0,0 +1,59 @@ +import React, { useRef } from "react"; +import Swiper from "react-native-swiper"; +import stylesFn from "@/styles/tab1.styles"; +import { useTheme } from "@react-navigation/native"; +import Colors from "@/constants/Colors"; +import RenderMediaItem from "./render-media-item"; + +interface CarouselWebProps { + data: any + onImagePress: (data: any) => void; +}; + +const CarouselWeb: React.FC = ({ + data, + onImagePress, +}) => { + const theme = useTheme(); + const styles = stylesFn(theme); + const swiperRef = useRef(null); + const videoRefs = useRef<{ [key: number]: any }>({}); + + const handleImagePress = (uri: string) => { + if (onImagePress) { + onImagePress(uri); + } + }; + + return ( + + {data.map(( + item: any, + index: number, + ) => ( + + ))} + + ); +}; + +export default CarouselWeb; diff --git a/components/ui/carousel/render-media-item.tsx b/components/ui/carousel/render-media-item.tsx new file mode 100644 index 00000000..eabe5d6f --- /dev/null +++ b/components/ui/carousel/render-media-item.tsx @@ -0,0 +1,91 @@ +import { + Image, + Platform, +} from "react-native"; +import Animated from "react-native-reanimated"; +import { ResizeMode, Video } from "expo-av"; +import { + TapGestureHandler, + State, +} from "react-native-gesture-handler"; + +import { stylesFn } from "@/styles/InfluencerCard.styles"; +import { useTheme } from "@react-navigation/native"; + +interface RenderMediaItemProps { + handleImagePress: (uri: string) => void; + height?: number; + index: number; + item: any; + videoRefs?: React.MutableRefObject<{ [key: number]: any }>; + width?: number; +} + +const RenderMediaItem: React.FC = ({ + handleImagePress, + height, + index, + item, + videoRefs, + width, +}) => { + const theme = useTheme(); + const styles = stylesFn(theme); + + if (item?.type === "image") { + return ( + { + if (nativeEvent.state === State.ACTIVE) { + handleImagePress(item.uri); + } + }} + > + + + + + ); + } + + return ( + {/* Login Prompt */} diff --git a/app/(auth)/forget-password.tsx b/app/(auth)/forget-password.tsx index 7bc709d4..aaa572ea 100644 --- a/app/(auth)/forget-password.tsx +++ b/app/(auth)/forget-password.tsx @@ -7,7 +7,6 @@ import { TextInput, Button } from "react-native-paper"; import { sendPasswordResetEmail } from "firebase/auth"; import { AuthApp } from "@/utils/auth"; import Toaster from "@/shared-uis/components/toaster/Toaster"; -import Toast from "react-native-toast-message"; import Colors from "@/constants/Colors"; const ForgotPasswordScreen = () => { @@ -37,7 +36,6 @@ const ForgotPasswordScreen = () => { return ( {/* Logo Section */} - { onPress={() => { handleResetPassword(); }} - style={styles.button} - labelStyle={styles.buttonText} > Reset Password diff --git a/app/(auth)/login.tsx b/app/(auth)/login.tsx index 95e4277d..95117b54 100644 --- a/app/(auth)/login.tsx +++ b/app/(auth)/login.tsx @@ -5,7 +5,6 @@ import { TextInput, Button } from "react-native-paper"; import { useRouter } from "expo-router"; import { useTheme } from "@react-navigation/native"; import fnStyles from "@/styles/login.styles"; -import Toast from "react-native-toast-message"; import Colors from "@/constants/Colors"; const LoginScreen = () => { @@ -23,7 +22,6 @@ const LoginScreen = () => { return ( - {/* Logo Section */} { diff --git a/app/(main)/(drawer)/(tabs)/_layout.tsx b/app/(main)/(drawer)/(tabs)/_layout.tsx index e99790f5..7706e35c 100644 --- a/app/(main)/(drawer)/(tabs)/_layout.tsx +++ b/app/(main)/(drawer)/(tabs)/_layout.tsx @@ -1,5 +1,4 @@ import React from "react"; -import FontAwesome from "@expo/vector-icons/FontAwesome"; import { router, Tabs } from "expo-router"; import Colors from "@/constants/Colors"; @@ -10,15 +9,18 @@ import NotificationIcon from "@/components/notifications/notification-icon"; import MenuIcon from "@/components/ui/menu-icon"; import { View } from "@/components/theme/Themed"; import DrawerToggleButton from "@/components/ui/drawer-toggle-button/DrawerToggleButton"; -import { Octicons } from "@expo/vector-icons"; import BrandSwitcher from "@/components/ui/brand-switcher"; - -const TabBarIcon = (props: { - name: React.ComponentProps["name"]; - color: string; -}) => { - return ; -}; +import { FontAwesomeIcon } from "@fortawesome/react-native-fontawesome"; +import { + faHandshake, + faComment, + faStar, +} from "@fortawesome/free-regular-svg-icons"; +import { + faFileSignature, + faPlusCircle, + faRightLeft, +} from "@fortawesome/free-solid-svg-icons"; const TabLayout = () => { const { xl } = useBreakpoints(); @@ -33,6 +35,7 @@ const TabLayout = () => { tabBarHideOnKeyboard: true, tabBarStyle: { display: xl ? "none" : "flex", // Hide the tab bar on desktop screens + paddingHorizontal: 8, }, headerTitleAlign: "left", headerTitleStyle: { @@ -46,7 +49,11 @@ const TabLayout = () => { options={{ title: "Explore Influencers", tabBarIcon: ({ color }) => ( - + ), headerLeft: () => xl ? ( @@ -54,9 +61,10 @@ const TabLayout = () => { ) : ( { name="collaborations" options={{ title: "Collaborations", - tabBarIcon: ({ color }) => , + tabBarIcon: ({ color }) => ( + + ), headerRight: () => , }} /> @@ -100,7 +114,11 @@ const TabLayout = () => { headerShown: false, title: "Create Collaborations", tabBarIcon: ({ color }) => ( - + ), }} /> @@ -108,7 +126,11 @@ const TabLayout = () => { name="messages" options={{ tabBarIcon: ({ color }) => ( - + ), title: "Messages", headerTitleAlign: "left", @@ -120,7 +142,11 @@ const TabLayout = () => { options={{ title: "Contracts", tabBarIcon: ({ color }) => ( - + ), headerRight: () => , }} diff --git a/app/(main)/(screens)/billing.tsx b/app/(main)/(screens)/(menu)/billing.tsx similarity index 100% rename from app/(main)/(screens)/billing.tsx rename to app/(main)/(screens)/(menu)/billing.tsx diff --git a/app/(main)/(screens)/brand-profile.tsx b/app/(main)/(screens)/(menu)/brand-profile.tsx similarity index 100% rename from app/(main)/(screens)/brand-profile.tsx rename to app/(main)/(screens)/(menu)/brand-profile.tsx diff --git a/app/(main)/(screens)/preferences.tsx b/app/(main)/(screens)/(menu)/preferences.tsx similarity index 100% rename from app/(main)/(screens)/preferences.tsx rename to app/(main)/(screens)/(menu)/preferences.tsx diff --git a/app/(main)/(screens)/profile.tsx b/app/(main)/(screens)/(menu)/profile.tsx similarity index 100% rename from app/(main)/(screens)/profile.tsx rename to app/(main)/(screens)/(menu)/profile.tsx diff --git a/app/(main)/(screens)/settings.tsx b/app/(main)/(screens)/(menu)/settings.tsx similarity index 100% rename from app/(main)/(screens)/settings.tsx rename to app/(main)/(screens)/(menu)/settings.tsx diff --git a/app/(main)/(screens)/CollaborationHistory.tsx b/app/(main)/(screens)/CollaborationHistory.tsx index 4877378a..d85131f8 100644 --- a/app/(main)/(screens)/CollaborationHistory.tsx +++ b/app/(main)/(screens)/CollaborationHistory.tsx @@ -1,36 +1,13 @@ -import BackButton from "@/components/ui/back-button/BackButton"; +import React from "react"; import AppLayout from "@/layouts/app-layout"; -import { stylesFn } from "@/styles/CollaborationHistory.styles"; -import { useTheme } from "@react-navigation/native"; -import React, { useState } from "react"; -import { View, ScrollView, StyleSheet } from "react-native"; -import { - TextInput, - Button, - Title, - Paragraph, - IconButton, - RadioButton, -} from "react-native-paper"; +import ScreenHeader from "@/components/ui/screen-header"; const CreateCollaborationScreen = () => { - const theme = useTheme(); - const styles = stylesFn(theme); return ( - - - - Collaboration History - - + ); }; diff --git a/app/(main)/(screens)/_layout.tsx b/app/(main)/(screens)/_layout.tsx index fb1d2e02..5c0ef35c 100644 --- a/app/(main)/(screens)/_layout.tsx +++ b/app/(main)/(screens)/_layout.tsx @@ -12,12 +12,7 @@ const ScreensLayout = () => { > - - - - - ); diff --git a/app/(main)/(screens)/collaboration-details/[pageID].tsx b/app/(main)/(screens)/collaboration-details/[pageID].tsx index a2589612..6a6e374b 100644 --- a/app/(main)/(screens)/collaboration-details/[pageID].tsx +++ b/app/(main)/(screens)/collaboration-details/[pageID].tsx @@ -1,77 +1,33 @@ -import CollaborationPage from "@/components/collaboration/CollaborationDetails"; -import { useEffect, useState } from "react"; -import { doc, getDoc } from "firebase/firestore"; -import { useLocalSearchParams } from "expo-router"; -import { FirestoreDB } from "@/utils/firestore"; +import BottomSheetActions from "@/components/BottomSheetActions"; +import CollaborationDetails from "@/components/collaboration/collaboration-details"; +import ScreenHeader from "@/components/ui/screen-header"; import AppLayout from "@/layouts/app-layout"; -import { ActivityIndicator, Chip } from "react-native-paper"; -import { ICollaboration } from "@/shared-libs/firestore/trendly-pro/models/collaborations"; -import { View } from "@/components/theme/Themed"; -import { ScrollView, StyleSheet } from "react-native"; - -interface Collaboration extends ICollaboration { - brandName: string; - paymentVerified: boolean; - brandDescription: string; -} +import { useLocalSearchParams } from "expo-router"; +import { useState } from "react"; const CollaborationDetailsScreen = () => { + const [isVisible, setIsVisible] = useState(false); const pageID = useLocalSearchParams().pageID; - const [collaboration, setCollaboration] = useState( - undefined - ); // Explicit type - const [loading, setLoading] = useState(true); - const [activeTab, setActiveTab] = useState("Overview"); - const fetchCollaboration = async () => { - if (!pageID) return; - try { - const collabRef = doc(FirestoreDB, "collaborations", pageID as string); - const snapshot = await getDoc(collabRef); - const data = snapshot.data() as ICollaboration; - if (!data) return; - - const brandRef = doc(FirestoreDB, "brands", data.brandId); - const brandSnapshot = await getDoc(brandRef); - const brandData = brandSnapshot.data(); - - setCollaboration({ - ...data, - brandName: brandData?.name || "Unknown Brand", - paymentVerified: brandData?.paymentMethodVerified || false, - brandDescription: brandData?.description || "", - }); - } catch (e) { - console.error(e); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - fetchCollaboration(); - }, [pageID]); - - if (loading) - return ( - - - - ); - - if (!collaboration) return null; return ( - {activeTab === "Overview" && ( - - )} + + + { + setIsVisible(false); + }} + /> ); }; export default CollaborationDetailsScreen; - -const styles = StyleSheet.create({}); diff --git a/app/(main)/_layout.tsx b/app/(main)/_layout.tsx index 70a42cf3..bd594e10 100644 --- a/app/(main)/_layout.tsx +++ b/app/(main)/_layout.tsx @@ -1,5 +1,4 @@ import { ChatContextProvider } from "@/contexts"; -import { BrandContextProvider } from "@/contexts/brand-context.provider"; import { Stack } from "expo-router"; const MainLayout = () => { diff --git a/app/(modal)/create-collaboration.tsx b/app/(modal)/create-collaboration.tsx index 66e7e899..dacf68ad 100644 --- a/app/(modal)/create-collaboration.tsx +++ b/app/(modal)/create-collaboration.tsx @@ -1,10 +1,8 @@ import AppLayout from "@/layouts/app-layout"; import React, { useEffect, useState } from "react"; import { - View, ScrollView, Platform, - Text, } from "react-native"; import { TextInput, @@ -15,18 +13,20 @@ import { RadioButton, Modal, } from "react-native-paper"; -import MapView, { Marker } from "react-native-maps"; import stylesFn from "@/styles/modal/UploadModal.styles"; import { useTheme } from "@react-navigation/native"; import { addDoc, collection } from "firebase/firestore"; import { FirestoreDB } from "@/utils/firestore"; import { AuthApp } from "@/utils/auth"; import Toaster from "@/shared-uis/components/toaster/Toaster"; -import Toast from "react-native-toast-message"; import { useBrandContext } from "@/contexts/brand-context.provider"; import Colors from "@/constants/Colors"; import { router } from "expo-router"; import * as Location from 'expo-location'; +import Select, { SelectItem } from "@/components/ui/select"; +import { Text, View } from "@/components/theme/Themed"; +import CreateCollaborationMap from "@/components/collaboration/create-collaboration/CreateCollaborationMap"; +import { COLLAB_TYPES, PLATFORM_TYPES, PROMOTION_TYPES } from "@/constants/CreateCollaborationForm"; const CreateCollaborationScreen = () => { const [collaborationName, setCollaborationName] = useState(""); @@ -34,9 +34,14 @@ const CreateCollaborationScreen = () => { const [budgetMin, setBudgetMin] = useState(""); const [budgetMax, setBudgetMax] = useState(""); const [numInfluencers, setNumInfluencers] = useState(1); - const [promotionType, setPromotionType] = useState(""); - const [collabType, setCollabType] = useState(""); - const [platform, setPlatform] = useState("Instagram"); + const [promotionType, setPromotionType] = useState([]); + const [collabType, setCollabType] = useState([]); + const [platform, setPlatform] = useState([ + { + label: "Instagram", + value: "Instagram", + }, + ]); const [location, setLocation] = useState("Remote"); const [links, setLinks] = useState([]); const [screen, setScreen] = useState(1); @@ -73,6 +78,11 @@ const CreateCollaborationScreen = () => { }, []); const addLink = () => { + if (!newLinkName || !newLinkUrl) { + Toaster.error("Please fill all fields"); + return; + } + setLinks([...links, { name: newLinkName, url: newLinkUrl }]); setNewLinkName(""); setNewLinkUrl(""); @@ -101,7 +111,7 @@ const CreateCollaborationScreen = () => { } const collabRef = collection(FirestoreDB, "collaborations"); - const docRef = await addDoc(collabRef, { + await addDoc(collabRef, { name: collaborationName, brandId: selectedBrand ? selectedBrand.id : "", managerId: AuthApp.currentUser?.uid, @@ -111,14 +121,14 @@ const CreateCollaborationScreen = () => { min: budgetMin, max: budgetMax, }, - promotionType, - collaborationType: collabType, + promotionType: promotionType[0].value, + collaborationType: collabType[0].value, numberOfInfluencersNeeded: numInfluencers, - platform, + platform: platform[0].value, location: { type: location, ...(location === "Physical" && { - name: "locationName", + name: "locationName", // TODO: Add location name using geocoding API latlong: { lat: mapRegion.latitude, long: mapRegion.longitude, @@ -142,38 +152,33 @@ const CreateCollaborationScreen = () => { if (screen === 1) { return ( - - - - {Platform.OS === "web" && ( - router.push("/collaborations")} - iconColor={Colors(theme).text} - /> - )} + { + Platform.OS === "web" && ( + router.push("/collaborations")} + /> + ) + } Create a Collaboration setCollaborationName(text)} style={styles.input} textColor={Colors(theme).text} @@ -184,119 +189,102 @@ const CreateCollaborationScreen = () => { text: Colors(theme).text, }, }} + value={collaborationName} /> setAboutCollab(text)} - multiline - textColor={Colors(theme).text} style={styles.input} + textColor={Colors(theme).text} + value={aboutCollab} /> setBudgetMin(text)} style={styles.budgetInput} textColor={Colors(theme).text} + value={budgetMin} /> setBudgetMax(text)} - textColor={Colors(theme).text} style={styles.budgetInput} + textColor={Colors(theme).text} + value={budgetMax} /> - - Number of Influencers Involved - - - setNumInfluencers(Math.max(1, numInfluencers - 1))} - /> - {numInfluencers} - setNumInfluencers(numInfluencers + 1)} - /> + + + Number of Influencers Involved: + + + setNumInfluencers(Math.max(1, numInfluencers - 1))} + style={styles.iconButton} + /> + + + {numInfluencers} + + + setNumInfluencers(numInfluencers + 1)} + style={styles.iconButton} + /> + - Promotion Type - setPromotionType(newValue)} - value={promotionType} + - - - Promotion Type: + setCollabType(selectedItems)} + value={collabType} /> - - - Platform - setPlatform(newValue)} - value={platform} + + - Platform: + setPromotionType(selectedItems)} - value={promotionType} - /> - - - Collaboration Type: - setPlatform(selectedItems)} - value={platform} - /> - - - - - ); - } - - if (screen == 2) { - return ( - - - - setScreen(1)} - style={{ - padding: 12, - }} - icon={() => ( - - )} - /> - Create a Collaboration - - - - - Location: - - setLocation(newValue)} - value={location} - > - - - - - - { - location === "Physical" && ( - setMapRegion(region)} - onFormattedAddressChange={onFormattedAddressChange} - /> - ) - } - - - { - links.map((link, index) => ( - - {link.name}: {link.url} - - )) - } - - - - - setIsModalVisible(false)} - visible={isModalVisible} - > - - - - - - ); - } - - if (screen === 3) { - return ( - - - - Collaboration Posted - - Your collaboration has been successfully posted. - - - - ); - } + return ( + + + + ); }; export default CreateCollaborationScreen; diff --git a/app/(modal)/edit-collaboration.tsx b/app/(modal)/edit-collaboration.tsx new file mode 100644 index 00000000..d2a05ca4 --- /dev/null +++ b/app/(modal)/edit-collaboration.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import CreateCollaboration from "@/components/create-collaboration"; +import AppLayout from "@/layouts/app-layout"; + +const EditCollaborationScreen = () => { + return ( + + + + ); +}; + +export default EditCollaborationScreen; diff --git a/app/_layout.tsx b/app/_layout.tsx index 32ae5cfd..301c00e7 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -139,10 +139,13 @@ const RootLayoutStack = () => { + diff --git a/components/BottomSheetActions.tsx b/components/BottomSheetActions.tsx index 1774fb12..40c283be 100644 --- a/components/BottomSheetActions.tsx +++ b/components/BottomSheetActions.tsx @@ -12,6 +12,7 @@ import { useChatContext, useNotificationContext } from "@/contexts"; import { FirestoreDB } from "@/utils/firestore"; import { doc, updateDoc } from "firebase/firestore"; import Toaster from "@/shared-uis/components/toaster/Toaster"; +import { useRouter } from "expo-router"; interface BottomSheetActionsProps { cardType: @@ -39,6 +40,7 @@ const BottomSheetActions = ({ const sheetRef = React.useRef(null); const [isMessageModalVisible, setIsMessageModalVisible] = React.useState(false); + const router = useRouter(); const { createGroupWithMembers, @@ -249,6 +251,18 @@ const BottomSheetActions = ({ handleClose(); }} /> + { + handleClose(); + router.push({ + pathname: "/edit-collaboration", + params: { + id: cardId, + }, + }); + }} + /> { diff --git a/components/collaboration/collaboration-details/ApplicationsTabContent.tsx b/components/collaboration/collaboration-details/ApplicationsTabContent.tsx index e79f146d..f42eb0ab 100644 --- a/components/collaboration/collaboration-details/ApplicationsTabContent.tsx +++ b/components/collaboration/collaboration-details/ApplicationsTabContent.tsx @@ -12,6 +12,7 @@ import BottomSheetActions from "@/components/BottomSheetActions"; import EmptyState from "@/components/ui/empty-state"; import Colors from "@/constants/Colors"; import { processRawAttachment } from "@/utils/attachments"; +import { useBreakpoints } from "@/hooks"; const ApplicationsTabContent = (props: any) => { const theme = useTheme(); @@ -20,6 +21,10 @@ const ApplicationsTabContent = (props: any) => { const [loading, setLoading] = useState(true); const [selectedApplication, setSelectedApplication] = useState(null); + const { + xl, + } = useBreakpoints(); + const fetchApplications = async () => { try { const applicationRef = collection( @@ -118,6 +123,8 @@ const ApplicationsTabContent = (props: any) => { keyExtractor={(item, index) => item.id + index} style={{ paddingBottom: 16, + width: xl ? 768 : '100%', + marginHorizontal: "auto", }} ItemSeparatorComponent={ () => ( diff --git a/components/collaboration/collaboration-details/InvitationsTabContent.tsx b/components/collaboration/collaboration-details/InvitationsTabContent.tsx index 7895576e..d6a615d8 100644 --- a/components/collaboration/collaboration-details/InvitationsTabContent.tsx +++ b/components/collaboration/collaboration-details/InvitationsTabContent.tsx @@ -21,6 +21,7 @@ import Toaster from "@/shared-uis/components/toaster/Toaster"; import { useInfluencers } from "@/hooks/request"; import EmptyState from "@/components/ui/empty-state"; import Colors from "@/constants/Colors"; +import { useBreakpoints } from "@/hooks"; const InvitationsTabContent = (props: any) => { const theme = useTheme(); @@ -42,6 +43,10 @@ const InvitationsTabContent = (props: any) => { pageID: props.pageID, }); + const { + xl, + } = useBreakpoints(); + const handleCollaborationInvite = async () => { try { setIsInviting(true); @@ -157,6 +162,8 @@ const InvitationsTabContent = (props: any) => { keyExtractor={(item) => item.id} style={{ paddingBottom: 16, + width: xl ? 768 : '100%', + marginHorizontal: "auto", }} ItemSeparatorComponent={ () => ( diff --git a/components/collaboration/collaboration-details/OverviewTabContent.tsx b/components/collaboration/collaboration-details/OverviewTabContent.tsx index 3ed035e2..0f59f989 100644 --- a/components/collaboration/collaboration-details/OverviewTabContent.tsx +++ b/components/collaboration/collaboration-details/OverviewTabContent.tsx @@ -8,6 +8,7 @@ import { import { useTheme } from "@react-navigation/native"; import { stylesFn } from "@/styles/collaboration-details/CollaborationDetails.styles"; import { CollaborationDetail } from "."; +import { useBreakpoints } from "@/hooks"; interface OverviewTabContentProps { collaboration: CollaborationDetail; @@ -19,6 +20,10 @@ const OverviewTabContent: React.FC = ({ const theme = useTheme(); const styles = stylesFn(theme); + const { + xl, + } = useBreakpoints(); + return ( = ({ paddingTop: 8, paddingHorizontal: 16, paddingBottom: 16, + width: xl ? 768 : '100%', + marginHorizontal: "auto", }} showsVerticalScrollIndicator={false} contentContainerStyle={{ diff --git a/components/create-collaboration/index.tsx b/components/create-collaboration/index.tsx new file mode 100644 index 00000000..e57c2c54 --- /dev/null +++ b/components/create-collaboration/index.tsx @@ -0,0 +1,275 @@ +import React, { useEffect, useState } from "react"; +import { AuthApp } from "@/utils/auth"; +import Toaster from "@/shared-uis/components/toaster/Toaster"; +import { useBrandContext } from "@/contexts/brand-context.provider"; +import { router, useLocalSearchParams } from "expo-router"; +import * as Location from 'expo-location'; +import { SelectItem } from "@/components/ui/select"; +import ScreenOne from "@/components/create-collaboration/screen-one"; +import ScreenTwo from "@/components/create-collaboration/screen-two"; +import ScreenThree from "@/components/create-collaboration/screen-three"; +import { useCollaborationContext } from "@/contexts"; +import { SocialPlatform } from "@/shared-libs/firestore/trendly-pro/constants/social-platform"; +import { PromotionType } from "@/shared-libs/firestore/trendly-pro/constants/promotion-type"; +import { CollaborationType } from "@/shared-libs/firestore/trendly-pro/constants/collaboration-type"; + +const CreateCollaboration = () => { + const [collaborationName, setCollaborationName] = useState(""); + const [aboutCollab, setAboutCollab] = useState(""); + const [budgetMin, setBudgetMin] = useState(""); + const [budgetMax, setBudgetMax] = useState(""); + const [numInfluencers, setNumInfluencers] = useState(1); + const [promotionType, setPromotionType] = useState([]); + const [collabType, setCollabType] = useState([]); + const [platform, setPlatform] = useState([ + { + label: "Instagram", + value: "Instagram", + }, + ]); + const params = useLocalSearchParams(); + const [location, setLocation] = useState("Remote"); + const [formattedAddress, setFormattedAddress] = useState(""); + const [links, setLinks] = useState([]); + const [screen, setScreen] = useState(1); + const [isModalVisible, setIsModalVisible] = useState(false); + const [newLinkName, setNewLinkName] = useState(""); + const { selectedBrand } = useBrandContext(); + const [newLinkUrl, setNewLinkUrl] = useState(""); + const [mapRegion, setMapRegion] = useState({ + latitude: 37.78825, + longitude: -122.4324, + latitudeDelta: 0.0922, + longitudeDelta: 0.0421, + }); + + const type = params.id ? "Edit" : "Add"; + + const { + getCollaborationById, + createCollaboration, + updateCollaboration, + } = useCollaborationContext(); + + useEffect(() => { + async function getCurrentLocation() { + let { status } = await Location.requestForegroundPermissionsAsync(); + if (status !== 'granted') { + alert('Permission to access location was denied'); + return; + } + + let location = await Location.getCurrentPositionAsync({}); + setMapRegion({ + ...mapRegion, + latitude: location.coords.latitude, + longitude: location.coords.longitude, + }); + } + + getCurrentLocation(); + }, []); + + const fetchCollaboration = async ( + id: string, + ) => { + const collaboration = await getCollaborationById(id); + setCollaborationName(collaboration.name); + setAboutCollab(collaboration.description || ""); + setBudgetMin(collaboration.budget.min?.toString() || ""); + setBudgetMax(collaboration.budget.max?.toString() || ""); + setNumInfluencers(collaboration.numberOfInfluencersNeeded); + setPromotionType([ + { + label: collaboration.promotionType, + value: collaboration.promotionType, + }, + ]); + setCollabType([ + { + label: collaboration.collaborationType, + value: collaboration.collaborationType, + }, + ]); + setPlatform([ + { + label: collaboration.platform, + value: collaboration.platform, + }, + ]); + setLocation(collaboration.location.type); + setLinks(collaboration.externalLinks || []); + if (collaboration.location.name && collaboration.location.latlong) { + setFormattedAddress(collaboration.location.name); + setMapRegion({ + latitude: collaboration.location.latlong.lat, + longitude: collaboration.location.latlong.long, + latitudeDelta: 0.0922, + longitudeDelta: 0.0421, + }); + } + } + + useEffect(() => { + if (params.id && typeof params.id === "string") { + fetchCollaboration(params.id); + } + }, []); + + const addLink = () => { + if (!newLinkName || !newLinkUrl) { + Toaster.error("Please fill all fields"); + return; + } + + setLinks([...links, { name: newLinkName, url: newLinkUrl }]); + setNewLinkName(""); + setNewLinkUrl(""); + setIsModalVisible(false); + }; + + const onFormattedAddressChange = (address: string) => { + setFormattedAddress(address); + } + + const handleCollaboration = async ( + data: any, + ): Promise => { + if (params.id && typeof params.id === "string") { + await updateCollaboration(params.id, data); + } else { + await createCollaboration(data) + } + } + + const submitCollaboration = async () => { + try { + if (!AuthApp.currentUser) { + console.error("User not logged in"); + } + + if ( + !collaborationName || + !aboutCollab || + !budgetMin || + !budgetMax || + !promotionType || + !collabType || + !numInfluencers || + !platform || + !location + ) { + Toaster.error("Please fill all fields"); + return; + } + + let locationAddress = {}; + if (location === "Physical" && mapRegion.latitude && mapRegion.longitude) { + locationAddress = { + name: formattedAddress, + latlong: { + lat: mapRegion.latitude, + long: mapRegion.longitude, + }, + }; + } + + await handleCollaboration({ + name: collaborationName, + brandId: selectedBrand ? selectedBrand.id : "", + managerId: AuthApp.currentUser?.uid as string, + description: aboutCollab, + timeStamp: Date.now(), + budget: { + min: Number(budgetMin), + max: Number(budgetMax), + }, + promotionType: promotionType[0].value as PromotionType, + collaborationType: collabType[0].value as CollaborationType, + numberOfInfluencersNeeded: numInfluencers, + platform: platform[0].value as SocialPlatform, + location: { + type: location, + ...locationAddress, + }, + externalLinks: links, + status: "active", + }).then(() => { + setScreen(3); + setTimeout(() => { + router.dismiss(1); + router.push("/collaborations"); + }, 3000); + }); + } catch (error) { + console.error(error); + } + }; + + if (screen === 1) { + return ( + + ); + } + + if (screen == 2) { + return ( + + ); + } + + if (screen === 3) { + return ( + + ); + } +}; + +export default CreateCollaboration; diff --git a/components/create-collaboration/screen-one.tsx b/components/create-collaboration/screen-one.tsx new file mode 100644 index 00000000..22537e33 --- /dev/null +++ b/components/create-collaboration/screen-one.tsx @@ -0,0 +1,208 @@ +import { Platform, Pressable, ScrollView } from "react-native"; + +import { COLLAB_TYPES, PLATFORM_TYPES, PROMOTION_TYPES } from "@/constants/CreateCollaborationForm"; +import { Text, View } from "../theme/Themed"; +import { Paragraph, TextInput } from "react-native-paper"; +import Colors from "@/constants/Colors"; +import { useTheme } from "@react-navigation/native"; + +import stylesFn from "@/styles/modal/UploadModal.styles"; +import { FontAwesomeIcon } from "@fortawesome/react-native-fontawesome"; +import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons"; +import Select, { SelectItem } from "../ui/select"; +import Button from "../ui/button"; +import Toaster from "@/shared-uis/components/toaster/Toaster"; +import React from "react"; +import ScreenHeader from "../ui/screen-header"; + +interface ScreenOneProps { + type: "Add" | "Edit"; + data: { + collaborationName: string; + aboutCollab: string; + budgetMin: string; + budgetMax: string; + numInfluencers: number; + promotionType: SelectItem[]; + collabType: SelectItem[]; + platform: SelectItem[]; + }; + setScreen: React.Dispatch>; + setState: { + collaborationName: React.Dispatch>; + aboutCollab: React.Dispatch>; + budgetMin: React.Dispatch>; + budgetMax: React.Dispatch>; + numInfluencers: React.Dispatch>; + promotionType: React.Dispatch>; + collabType: React.Dispatch>; + platform: React.Dispatch>; + }; +} + +const ScreenOne: React.FC = ({ + type, + data, + setScreen, + setState, +}) => { + const theme = useTheme(); + const styles = stylesFn(theme); + + return ( + <> + + + + setState.collaborationName(text)} + style={styles.input} + textColor={Colors(theme).text} + theme={{ + colors: { + primary: Colors(theme).primary, + placeholder: Colors(theme).text, + text: Colors(theme).text, + }, + }} + value={data.collaborationName} + /> + setState.aboutCollab(text)} + style={styles.input} + textColor={Colors(theme).text} + value={data.aboutCollab} + /> + + setState.budgetMin(text)} + style={styles.budgetInput} + textColor={Colors(theme).text} + value={data.budgetMin} + /> + setState.budgetMax(text)} + style={styles.budgetInput} + textColor={Colors(theme).text} + value={data.budgetMax} + /> + + + + Number of Influencers Involved: + + + setState.numInfluencers(Math.max(1, data.numInfluencers - 1))} + style={styles.iconButton} + + > + + + + + {data.numInfluencers} + + + setState.numInfluencers(data.numInfluencers + 1)} + style={styles.iconButton} + > + + + + + + Promotion Type: + setState.collabType(selectedItems)} + value={data.collabType} + /> + + + Platform: +