Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions app/(main)/(drawer)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@ import { Drawer } from "expo-router/drawer";
import DrawerMenuContent from "@/components/drawer-layout/DrawerMenuContent";
import BackButton from "@/components/ui/back-button/BackButton";
import { useBreakpoints } from "@/hooks";
import { BrandProtectedScreen } from "@/layouts/protected";

const DrawerLayout = () => {
const { xl } = useBreakpoints();

return (
<Drawer
backBehavior="history"
drawerContent={() => <DrawerMenuContent />}
screenOptions={{
drawerType: xl ? "permanent" : "slide",
headerShown: false,
headerLeft: () => xl ? null : <BackButton />,
}}
>
<Drawer.Screen
name="(tabs)"
options={{
<BrandProtectedScreen>
<Drawer
backBehavior="history"
drawerContent={() => <DrawerMenuContent />}
screenOptions={{
drawerType: xl ? "permanent" : "slide",
headerShown: false,
headerLeft: () => xl ? null : <BackButton />,
}}
/>
</Drawer>
>
<Drawer.Screen
name="(tabs)"
options={{
headerShown: false,
}}
/>
</Drawer>
</BrandProtectedScreen>
);
};

Expand Down
3 changes: 3 additions & 0 deletions app/(main)/(screens)/(onboarding)/onboarding-your-brand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ const OnboardingScreen = () => {
} = useAuthContext();

const handleCreateBrand = async () => {
setIsSubmitting(true);
if (!user) {
Toaster.error("User not found");
setIsSubmitting(false);
return;
}

if (!brandData.name) {
Toaster.error('Brand name is required');
setIsSubmitting(false);
return;
}

Expand Down
19 changes: 17 additions & 2 deletions app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { View } from "@/components/theme/Themed"
import { Image } from "react-native";
import { View } from "@/components/theme/Themed";

const Index = () => {
return (
<View></View>
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Image
source={require("@/assets/images/splash.png")}
style={{
width: '100%',
height: '100%',
}}
/>
</View>
);
};

Expand Down
110 changes: 110 additions & 0 deletions components/shimmers/explore-influencer-shimmer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { useTheme } from '@react-navigation/native';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faBell, faChevronDown } from '@fortawesome/free-solid-svg-icons';

import AppLayout from '@/layouts/app-layout';
import Colors from '@/constants/Colors';
import Shimmer from '@/shared-uis/components/shimmer';
import { View } from '../theme/Themed';

const ExploreInfluencerShimmer = () => {
const theme = useTheme();

return (
<AppLayout>
<View style={styles.container}>
<View style={styles.header}>
<View style={styles.headerLeft}>
<Shimmer width={80} height={36} />
<FontAwesomeIcon
icon={faChevronDown}
size={20}
color={Colors(theme).text}
/>
</View>
<FontAwesomeIcon
icon={faBell}
size={22}
color={Colors(theme).text}
/>
</View>

<View style={styles.searchContainer}>
<Shimmer width="100%" height={40} />
</View>

<View style={styles.profileSection}>
<Shimmer width={50} height={50} />
<View style={styles.profileInfo}>
<Shimmer width={150} height={20} />
<Shimmer width={100} height={16} />
</View>
</View>

<Shimmer width="100%" height={300} />

<View style={styles.metrics}>
<Shimmer width={50} height={24} />
<Shimmer width={50} height={24} />
</View>

<Shimmer width="100%" height={40} />

<View style={styles.bottomNav}>
{[...Array(5)].map((_, index) => (
<Shimmer
key={index}
width={56}
height={48}
/>
))}
Comment thread
dev-rathore marked this conversation as resolved.
Resolved
</View>
</View>
</AppLayout>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 16,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
headerLeft: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
searchContainer: {
marginBottom: 16,
},
profileSection: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
marginBottom: 16,
},
profileInfo: {
gap: 4,
},
metrics: {
flexDirection: 'row',
gap: 16,
marginVertical: 16,
},
bottomNav: {
flexDirection: 'row',
justifyContent: 'center',
gap: 16,
marginTop: 'auto',
},
});

export default ExploreInfluencerShimmer;
4 changes: 4 additions & 0 deletions constants/Colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default (theme: Theme) => ({
tag: "#5f6368",
tagForeground: "#f1f3f4",
outline: "#538BA6",
shimmerBackground: "#1E1E1E",
shimmerOverlay: "#1b1b1b",
}
: {
card: "#fff",
Expand All @@ -33,6 +35,8 @@ export default (theme: Theme) => ({
tag: "#f1f3f4",
tagForeground: "#5f6368",
outline: "#054463",
shimmerBackground: "#f1f3f4",
shimmerOverlay: "#eee",
}),
aliceBlue: "#E9F1F7",
amber: "#FFBF00",
Expand Down
92 changes: 92 additions & 0 deletions layouts/protected/brand-protected-screen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { PropsWithChildren, useEffect, useState } from "react";
import { ActivityIndicator, Platform } from "react-native";
import { useTheme } from "@react-navigation/native";
import { useRouter } from "expo-router";
import { collection, getDocs, query, where } from "firebase/firestore";

import { View } from "@/components/theme/Themed";
import { useAuthContext } from "@/contexts";
import Colors from "@/constants/Colors";
import ExploreInfluencerShimmer from "@/components/shimmers/explore-influencer-shimmer";
import { FirestoreDB } from "@/utils/firestore";

interface BrandProtectedScreenProps extends PropsWithChildren { }

const BrandProtectedScreen: React.FC<BrandProtectedScreenProps> = ({
children,
}) => {
const [hasBrandWithManagerId, setHasBrandWithManagerId] = useState(false);
const router = useRouter();

const {
manager,
} = useAuthContext();

const fetchBrands = async (
managerId: string
): Promise<void> => {
const brandsCollection = collection(FirestoreDB, "brands");

const brandsSnapshot = await getDocs(brandsCollection);

for (const brandDoc of brandsSnapshot.docs) {
const brandId = brandDoc.id;

const membersCollection = collection(FirestoreDB, `brands/${brandId}/members`);
const membersQuery = query(membersCollection, where("managerId", "==", managerId));
const membersSnapshot = await getDocs(membersQuery);

if (!membersSnapshot.empty) {
setHasBrandWithManagerId(true);
return;
}
}

// If the manager has no brands, redirect to onboarding
router.replace({
pathname: "/onboarding-your-brand",
params: {
firstBrand: "true",
},
});
};
Comment thread
dev-rathore marked this conversation as resolved.
Resolved

useEffect(() => {
if (!manager?.id) return;

fetchBrands(manager.id);
}, [manager]);

if (!hasBrandWithManagerId) {
return <LoadingScreen />;
}

return <>{children}</>;
};

const LoadingScreen: React.FC = () => {
const theme = useTheme();

if (Platform.OS === "web") {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<ActivityIndicator
size="large"
color={Colors(theme).primary}
/>
</View>
);
}

return (
<ExploreInfluencerShimmer />
);
}

export default BrandProtectedScreen;
3 changes: 3 additions & 0 deletions layouts/protected/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import BrandProtectedScreen from "./brand-protected-screen";

export { BrandProtectedScreen };
2 changes: 1 addition & 1 deletion shared-uis