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
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
client:
name: Client (typecheck, lint, tests, build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck client
run: pnpm --filter client typecheck

- name: Lint client
run: pnpm --filter client lint

- name: Unit tests
run: pnpm --filter client test:unit

- name: Web export (bundle check)
run: pnpm --filter client build
env:
# Placeholder values: the bundle must build without real credentials
EXPO_PUBLIC_SUPABASE_URL: https://placeholder.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY: placeholder-anon-key

bots:
name: Bots (typecheck, syntax)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck slack-bot
run: pnpm --filter slack-bot typecheck

- name: Syntax-check discord bot
run: |
for f in apps/discord-event-bot/src/*.js; do
node --check "$f"
done
2 changes: 2 additions & 0 deletions ANALYSIS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
> **Historical snapshot.** This document describes the project at an earlier stage of development and is kept for reference. Parts of it no longer match the codebase — see [README.md](README.md) for the current state.

# Universify Project Analysis

## Executive Summary
Expand Down
2 changes: 2 additions & 0 deletions DATABASE_SETUP_COMPLETE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
> **Historical snapshot.** This document describes the project at an earlier stage of development and is kept for reference. Parts of it no longer match the codebase — see [README.md](README.md) for the current state.

# Complete Database Setup Guide for Universify

## Overview
Expand Down
2 changes: 2 additions & 0 deletions GOOGLE_INTEGRATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
> **Historical snapshot.** This document describes the project at an earlier stage of development and is kept for reference. Parts of it no longer match the codebase — see [README.md](README.md) for the current state.

# Google Sign-In & Calendar Integration Summary

This document summarizes all the changes made to integrate Google Sign-In and Google Calendar functionality into Universify.
Expand Down
2 changes: 2 additions & 0 deletions IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
> **Historical snapshot.** This document describes the project at an earlier stage of development and is kept for reference. Parts of it no longer match the codebase — see [README.md](README.md) for the current state.

# Universify - Implementation Summary

## Overview
Expand Down
2 changes: 2 additions & 0 deletions INTEGRATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
> **Historical snapshot.** This document describes the project at an earlier stage of development and is kept for reference. Parts of it no longer match the codebase — see [README.md](README.md) for the current state.

# Calendar Integration Summary

## What Was Integrated
Expand Down
92 changes: 55 additions & 37 deletions README.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions apps/client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ expo-env.d.ts
# Metro
.metro-health-check*

# Playwright
test-results/
playwright-report/

# debug
npm-debug.*
yarn-debug.*
Expand Down
51 changes: 25 additions & 26 deletions apps/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ A comprehensive cross-platform event aggregation and discovery application built

- **Profile & Settings**
- User profile with stats (events created, saved, interests)
- Account settings (name, email, password change)
- Account settings (name, university; sign-in managed by Google)
- Preferences (home page, calendar days, category interests)
- Appearance (theme, font size, accessibility)
- Logout functionality
Expand Down Expand Up @@ -134,51 +134,50 @@ apps/client/

### Prerequisites

- Node.js 18+
- npm or pnpm
- Expo CLI
- Node.js 18+
- pnpm 10+ (this is a pnpm workspace — use pnpm, not npm)

### Installation

```bash
# Navigate to client directory
cd apps/client

# Install dependencies
npm install
# From the repository root
pnpm install

# Start development server
npm start
# Start the development server
cd apps/client
pnpm start
```

### Running on Different Platforms

```bash
# Web
npm run web
pnpm web

# iOS (requires Mac)
npm run ios
pnpm ios

# Android
npm run android
pnpm android
```

## 🧪 Demo Accounts
### Useful scripts

Use these accounts to test the application:

1. **Demo User**
- Email: `demo@cmu.edu`
- Password: `Demo123!`
```bash
pnpm typecheck # TypeScript check
pnpm lint # ESLint
pnpm test:unit # Unit tests (dedupe, recurrence, layout, recommendations)
pnpm test:e2e # Playwright E2E suite (starts the web server itself)
pnpm build # Static web export to dist/
pnpm seed # Seed mock events into Supabase (needs service-role key)
```

2. **Student User**
- Email: `student@andrew.cmu.edu`
- Password: `Student123!`
## 🧪 Trying It Out

3. **Test User**
- Email: `test@stanford.edu`
- Password: `Test123!`
Authentication is Google OAuth only, restricted to `@andrew.cmu.edu` /
`@cmu.edu` accounts — there are no password logins. Without Supabase
credentials in `.env`, the app runs in offline demo mode: it loads the
bundled mock events and keeps all changes in local state.

## 🎨 Design System

Expand Down
57 changes: 26 additions & 31 deletions apps/client/app/(auth)/callback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, Platform } from 'react-native';
import { router } from 'expo-router';
import { supabase } from '@/lib/supabase';
import { useAppTheme } from '@/hooks/useAppTheme';
import { AppPalette } from '@/constants/theme';

/**
* OAuth callback route for Google sign-in.
Expand All @@ -10,6 +12,8 @@ import { supabase } from '@/lib/supabase';
*/
export default function AuthCallbackScreen() {
const [error, setError] = useState<string | null>(null);
const { colors, fontScale } = useAppTheme();
const styles = React.useMemo(() => createStyles(colors, fontScale), [colors, fontScale]);

useEffect(() => {
if (Platform.OS !== 'web' || typeof window === 'undefined') {
Expand All @@ -29,9 +33,6 @@ export default function AuthCallbackScreen() {
}

if (!code) {
// #region agent log
if (typeof fetch !== 'undefined') fetch('http://127.0.0.1:7249/ingest/6ce6a0bd-b1d8-4a58-95c8-c0ef781b168b',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'callback.tsx:noCode',message:'Callback hit but no code in URL',data:{url:typeof window!=='undefined'?window.location.href:''},timestamp:Date.now(),hypothesisId:'A'})}).catch(()=>{});
// #endregion
// No code - might already have session or direct visit; go to app
const { data: { session } } = await supabase.auth.getSession();
if (session) {
Expand All @@ -43,17 +44,10 @@ export default function AuthCallbackScreen() {
}

try {
const { data: exchangeData, error: exchangeError } = await supabase.auth.exchangeCodeForSession(code);

// #region agent log
if (typeof fetch !== 'undefined') fetch('http://127.0.0.1:7249/ingest/6ce6a0bd-b1d8-4a58-95c8-c0ef781b168b',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'callback.tsx:exchange',message:'After exchangeCodeForSession',data:{hasCode:!!code,hasError:!!exchangeError,hasSession:!!exchangeData?.session,hasProviderToken:!!exchangeData?.session?.provider_token},timestamp:Date.now(),hypothesisId:'B'})}).catch(()=>{});
// #endregion
const { error: exchangeError } = await supabase.auth.exchangeCodeForSession(code);

if (exchangeError) {
console.error('Code exchange error:', exchangeError);
// #region agent log
if (typeof fetch !== 'undefined') fetch('http://127.0.0.1:7249/ingest/6ce6a0bd-b1d8-4a58-95c8-c0ef781b168b',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'callback.tsx:exchangeError',message:'Code exchange failed',data:{error:exchangeError.message},timestamp:Date.now(),hypothesisId:'B'})}).catch(()=>{});
// #endregion
setError(exchangeError.message);
setTimeout(() => router.replace('/(auth)/login'), 3000);
return;
Expand All @@ -77,30 +71,31 @@ export default function AuthCallbackScreen() {
<Text style={styles.errorText}>{error}</Text>
) : (
<>
<ActivityIndicator size="large" color="#FF6B6B" />
<ActivityIndicator size="large" color={colors.primary} />
<Text style={styles.message}>Completing sign-in...</Text>
</>
)}
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F8F9FA',
},
message: {
marginTop: 16,
fontSize: 16,
color: '#6B7280',
},
errorText: {
fontSize: 16,
color: '#DC2626',
textAlign: 'center',
paddingHorizontal: 24,
},
});
const createStyles = (colors: AppPalette, fontScale: number) =>
StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.background,
},
message: {
marginTop: 16,
fontSize: 16 * fontScale,
color: colors.textSecondary,
},
errorText: {
fontSize: 16 * fontScale,
color: colors.danger,
textAlign: 'center',
paddingHorizontal: 24,
},
});
Loading
Loading