Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd5f45d
Merge pull request #90 from techstartucalgary/mobile
tahaminachy43 Mar 22, 2026
9e72eec
sign up form update
tahaminachy43 Mar 22, 2026
23a5dc8
Styling Changes
tahaminachy43 Mar 23, 2026
5fe3701
(Update) Added Organization Adding in Guest Flow
keeryn04 Apr 1, 2026
e1de1c8
(Update) Styling Fixes for Guest, Signup
keeryn04 Apr 1, 2026
0c0a5b1
(Update) Change Org and Title in Update Profile, Swapped Social Links…
keeryn04 Apr 1, 2026
af1d6aa
Merge pull request #99 from techstartucalgary/mobile-guest-work
keeryn04 Apr 2, 2026
abf9f9a
(Update) Organization, Role Properly Saved
keeryn04 Apr 3, 2026
6817c67
(Fix) Event Lobby Being Stuck
keeryn04 Apr 10, 2026
676a3cd
Merge branch 'Mobile-LinkedInAuth' into mobile
tahaminachy43 Apr 10, 2026
3236a05
Revert "Merge branch 'Mobile-LinkedInAuth' into mobile"
lnqminh3003 Apr 10, 2026
5fd812a
Merge pull request #107 from techstartucalgary/mobile
tahaminachy43 Apr 10, 2026
7e5fa89
(Update) Swapped Social Link Formatting
keeryn04 Apr 10, 2026
a4620c6
(Progress) Added LinkedIn Linking to UpdateProfile
keeryn04 Apr 22, 2026
d3ad9f8
Merge branch 'mobile-linkedin-link' into mobile-social-link-refactor
keeryn04 Apr 22, 2026
c98266e
Merge branch 'main' into mobile
lnqminh3003 Apr 30, 2026
e324100
(Progress) Websocket Connection Implementation
keeryn04 Apr 30, 2026
d8ba21b
(Update) Profile Photo to Top of Update Profile
keeryn04 Apr 30, 2026
69952f0
(Update) Better Hook Handling
keeryn04 Apr 30, 2026
36350bc
(Update) Link Linkedin to Existing User
keeryn04 Apr 30, 2026
3f8daa8
Merge branch 'Mobile-Styling' into mobile
tahaminachy43 Apr 30, 2026
341de7c
Merge pull request #112 from techstartucalgary/mobile-social-link-ref…
keeryn04 Apr 30, 2026
422fa6e
(Update) Removed LinkedIn Auth in Update Profile
keeryn04 Apr 30, 2026
e091202
(Update) Changed Links to Label Display
keeryn04 Apr 30, 2026
a42e893
(Fix) Can View Previous Game State from Event Page
keeryn04 Apr 30, 2026
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
2 changes: 1 addition & 1 deletion shatter-mobile/app/(tabs)/EventsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import AnimatedTab from "../../src/components/AnimatedTab";
import EventCard from "../../src/components/events/EventCard";
import AnimatedTab from "../../src/components/general/AnimatedTab";
import EventIB from "../../src/interfaces/Event";
import { getUserEvents } from "../../src/services/event.service";
import { EventPageStyling as styles } from "../../src/styling/EventPage.styles";
Expand Down
14 changes: 7 additions & 7 deletions shatter-mobile/app/(tabs)/JoinEventPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router";
import { useState } from "react";
import {
ActivityIndicator,
ImageBackground,
Text,
TextInput,
TouchableOpacity,
View,
ActivityIndicator,
ImageBackground,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import AnimatedTab from "../../src/components/AnimatedTab";
import { useAuth } from "../../src/components/context/AuthContext";
import AnimatedTab from "../../src/components/general/AnimatedTab";
import QRScannerBox from "../../src/components/new-events/QRScannerBox";
import { JoinEventStyling as styles } from "../../src/styling/JoinEventPage.styles";

Expand Down
83 changes: 60 additions & 23 deletions shatter-mobile/app/(tabs)/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useFocusEffect, useRouter } from "expo-router";
import { useCallback, useEffect, useState } from "react";
import { useRouter } from "expo-router";
import { useEffect } from "react";
import {
Image,
ImageBackground,
Expand All @@ -10,33 +10,30 @@ import {
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { SvgUri } from "react-native-svg";
import AnimatedTab from "../../src/components/AnimatedTab";
import { useAuth } from "../../src/components/context/AuthContext";
import AnimatedTab from "../../src/components/general/AnimatedTab";
import { ProfilePageStyling as styles } from "../../src/styling/ProfilePage.styles";

export default function Profile() {
const { user, logout } = useAuth();
const router = useRouter();
const [socialLinks, setSocialLinks] = useState(user?.socialLinks || []);

//update local form
useFocusEffect(
useCallback(() => {
setSocialLinks(user?.socialLinks || []);
}, [user]),
);

//not logged in
// not logged in
useEffect(() => {
if (!user) {
router.replace("/UserPages/Login");
}
}, [user]);

if (!user) {
return null; //don't render profile content while redirecting
return null;
}

const social = user.socialLinks;

const hasSocialLinks =
!!social?.linkedin || !!social?.github || (social?.other?.length ?? 0) > 0;

//logged in
if (user && !user.isGuest) {
return (
Expand All @@ -53,6 +50,7 @@ export default function Profile() {
Welcome back, {user.name || "Networker"}!
</Text>
</View>

<View style={styles.container}>
<ScrollView
contentContainerStyle={{ alignItems: "center" }}
Expand All @@ -62,15 +60,34 @@ export default function Profile() {
source={{ uri: user.profilePhoto }}
style={styles.avatar}
/>

<Text style={styles.subtitleText}>{user.email}</Text>

{socialLinks.length === 0 && (
{/* Empty */}
{!hasSocialLinks && (
<Text style={styles.emptyText}>
No social links added yet.
</Text>
)}

{socialLinks.map((link, index) => (
{/* LinkedIn */}
{social?.linkedin && (
<View style={styles.linkContainer}>
<Text style={styles.linkLabel}>LinkedIn</Text>
<Text style={styles.linkUrl}>{social.linkedin}</Text>
</View>
)}

{/* GitHub */}
{social?.github && (
<View style={styles.linkContainer}>
<Text style={styles.linkLabel}>GitHub</Text>
<Text style={styles.linkUrl}>{social.github}</Text>
</View>
)}

{/* Other Links */}
{social?.other?.map((link, index) => (
<View key={index} style={styles.linkContainer}>
<Text style={styles.linkLabel}>{link.label}</Text>
<Text style={styles.linkUrl}>{link.url}</Text>
Expand Down Expand Up @@ -111,6 +128,7 @@ export default function Profile() {
Welcome, {user.name || "Networker"}!
</Text>
</View>

<View style={styles.container}>
<ScrollView
contentContainerStyle={{ alignItems: "center" }}
Expand All @@ -119,36 +137,55 @@ export default function Profile() {
<SvgUri
uri={
user.profilePhoto ??
`https://api.dicebear.com/9.1.1/initials/png?seed=${encodeURIComponent(user.name || "Unknown")}&size=128`
`https://api.dicebear.com/9.1.1/initials/png?seed=${encodeURIComponent(
user.name || "Unknown",
)}&size=128`
}
style={styles.avatar}
/>

<Text style={styles.notice}>
You are logged in as a guest. Some features may be limited.
</Text>

{!user._id && (
<Text style={styles.notice}>
To upgrade your account, join an event and then come back
here to set it up!
</Text>
)}

{socialLinks.length === 0 && (
{/* Empty */}
{!hasSocialLinks && (
<Text style={styles.emptyText}>
No social links added yet.
</Text>
)}

{socialLinks.map((link, index) => (
{/* LinkedIn */}
{social?.linkedin && (
<View style={styles.linkContainer}>
<Text style={styles.linkLabel}>LinkedIn</Text>
<Text style={styles.linkUrl}>{social.linkedin}</Text>
</View>
)}

{/* GitHub */}
{social?.github && (
<View style={styles.linkContainer}>
<Text style={styles.linkLabel}>GitHub</Text>
<Text style={styles.linkUrl}>{social.github}</Text>
</View>
)}

{/* Other Links */}
{social?.other?.map((link, index) => (
<View key={index} style={styles.linkContainer}>
<>
<Text style={styles.linkLabel}>{link.label}</Text>
<Text style={styles.linkUrl}>{link.url}</Text>
</>
<Text style={styles.linkLabel}>{link.label}</Text>
<Text style={styles.linkUrl}>{link.url}</Text>
</View>
))}

{/* Guest user who has joined event / has userId */}
{user._id && (
<View>
<TouchableOpacity
Expand Down
46 changes: 15 additions & 31 deletions shatter-mobile/app/EventPages/EventLobby.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,35 @@
import { useGame } from "@/src/components/context/GameContext";
import { EventState } from "@/src/interfaces/Event";
import { getEventById } from "@/src/services/event.service";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { ActivityIndicator, Text, TouchableOpacity, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { EventLobbyStyling as styles } from "../../src/styling/EventLobby.styles";

const POLL_INTERVAL = 3000; //3 seconds

export default function EventLobby() {
const { eventId } = useLocalSearchParams<{ eventId: string }>(); //avoid race conditions with initializeGame
const [status, setStatus] = useState(EventState.UPCOMING);
const { gameState } = useGame();

//TODO: Websocket for game loading
useEffect(() => {
if (!eventId) return; //don't start polling until eventId is set

const interval = setInterval(async () => {
const res = await getEventById(eventId);
const event = res?.event;
if (!event) return;

setStatus(event.currentState);
if (!eventId) return;
if (gameState.progress !== EventState.IN_PROGRESS) return;

if (event.currentState === EventState.IN_PROGRESS) {
clearInterval(interval);
console.log(gameState);

router.replace({
pathname: "/GamePages/Game",
});
}
}, POLL_INTERVAL);

return () => clearInterval(interval);
}, [eventId]);
router.replace({
pathname: "/GamePages/Game",
params: { eventId },
});
}, [gameState.progress, eventId]);

return (
<SafeAreaView style={styles.safe}>
<View style={styles.container}>
<Text style={styles.title}>Successfully Joined!</Text>

{status === EventState.UPCOMING && (
<>
<Text style={styles.text}>Waiting for the event to start...</Text>
<ActivityIndicator size="large" style={styles.indicator} />
</>
)}
<>
<Text style={styles.text}>Waiting for the event to start...</Text>
<ActivityIndicator size="large" style={styles.indicator} />
</>

{/* Leave Game Button */}
<TouchableOpacity
Expand Down
4 changes: 2 additions & 2 deletions shatter-mobile/app/GamePages/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import { ImageBackground, Text, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import FullPageLoader from "../../src/components/FullPageLoader";
import IcebreakerGame from "../../src/components/games/IcebreakerGame";
import FullPageLoader from "../../src/components/general/FullPageLoader";
import { getEventById } from "../../src/services/event.service";
import { GamePageStyling as styles } from "../../src/styling/GamePage.styles";

Expand Down Expand Up @@ -60,7 +60,7 @@ const GamePage = () => {
</View>

<View style={styles.gameContainer}>
<IcebreakerGame event={event}/>
<IcebreakerGame event={event} />
</View>
</View>
</SafeAreaView>
Expand Down
Loading
Loading