Skip to content

Commit 78828f3

Browse files
merge master (#406)
* feat: update docs (#400) * feat(docs): update docs to reflect v2 * feat(docs): add setup guides for be/fe/app * feat(backend): create and adopt `/api/rooms` endpoint for room data (#401) * create `/api/rooms` endpoint for room data * Remove name and flatten data in bookings endpoint * Use new endpoints on room page * Add rooms to search modal * feat: use common folder for shared code (e.g. data types) (#402) * chore: fix cd * chore: fix backend.dockerfile * feat: integrate with CSESoc GraphQL API (#403) * Rewrite backend to use Hasura instead of timetable API * Use additional data in frontend * Please the linter * Please the type checks * Show buildings before status is loaded * Add correct GraphQL endpoint * New Building images * fix: fix broken filters with new data * feat: add filter for whether ID is required * New Building images --------- Co-authored-by: 3bobchen <83627389+3bobchen@users.noreply.github.com>
1 parent ffcf15b commit 78828f3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1785
-3273
lines changed

.dockerignore

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
**/node_modules
5+
**/.pnp
6+
**/.pnp.js
7+
8+
# testing
9+
**/coverage
10+
11+
# next.js
12+
**/.next/
13+
**/out/
14+
15+
# production
16+
**/build
17+
**/dist
18+
19+
# misc
20+
**/.DS_Store
21+
**/*.pem
22+
23+
# debug
24+
**/npm-debug.log*
25+
**/yarn-debug.log*
26+
**/yarn-error.log*
27+
**/.pnpm-debug.log*
28+
29+
# local env files
30+
**/.env.local
31+
**/.env.development.local
32+
**/.env.test.local
33+
**/.env.production.local
34+
35+
# vercel
36+
**/.vercel
37+
38+
# typescript
39+
**/*.tsbuildinfo

.github/workflows/docker.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ jobs:
4646
- name: Build and push Docker image
4747
uses: docker/build-push-action@v4
4848
with:
49-
context: ${{ matrix.context }}
49+
context: .
5050
push: ${{ github.event_name != 'pull_request' }}
5151
platforms: linux/amd64
52-
file: ${{ matrix.context }}/Dockerfile
52+
file: ${{ matrix.context }}.dockerfile
5353
tags: |
5454
ghcr.io/csesoc/freerooms-${{ matrix.name }}:${{ github.sha }}
5555
ghcr.io/csesoc/freerooms-${{ matrix.name }}:latest

README.md

+22-5
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,38 @@ You can find a live build of Freerooms at [https://freerooms.csesoc.app](https:/
1717

1818
- Check which rooms are free:
1919

20-
<img src="docs/gallery.png" alt="Gallery" width="450px">
21-
<img src="docs/list.png" alt="Room List" width="450px">
20+
<img src="docs/browse.png" alt="Browse page" width="450px">
21+
22+
- Sort and filter by a range of criteria:
23+
24+
<img src="docs/sort.png" alt="Sort" width="150">
25+
<img src="docs/filter.png" alt="Filter" width="150px">
26+
27+
- See which buildings around you have free rooms on the map:
28+
29+
<img src="docs/map.png" alt="Map" width="450px">
2230

2331
- See the timetable for each room:
2432

2533
<img src="docs/timetable.png" alt="Room Timetable" width="450px">
2634

35+
- Quickly search for specific buildings or rooms:
36+
37+
<img src="docs/search.png" alt="Search modal" width="450px">
38+
39+
2740
## Future Plans
2841

2942
This project is rapidly expanding and our roadmap includes features such as:
3043

31-
- **Map View**: Find and navigate to free rooms near you.
32-
- **Search, Sort and Filter**: Find the perfect room for your needs.
44+
- **Detailed Room Information**: Information such as a room's type, how to book it, and all its aliases.
45+
- **Society Bookings**: Use data about society bookings and other bookings besides scheduled classes.
3346
- **Mobile App**: Use Freerooms anytime, anywhere!
3447

35-
# Our team
48+
# Local Setup
49+
50+
See the [backend](backend), [frontend](frontend) and [app](app) directories for instructions on setting up and running Freerooms locally.
51+
52+
# Our Team
3653

3754
We are a team that is part of CSESoc Development. See [TEAM.md](./TEAM.md) for more information on the current and previous team that contributed to the development of Freerooms.

app/App.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { NavigationContainer } from '@react-navigation/native';
22
import { getBuildings, getRooms } from './services/freerooms_api/endpoints';
3-
import { Room_Dictionary, Buildings } from './services/freerooms_api/api_types';
3+
import { Building, StatusResponse } from "@common/types";
44
import RootNavigator from './screens/Root/root_navigator';
55
import { StatusBar } from 'expo-status-bar';
66
import { useEffect, useState } from 'react';
77
import { FreeRoomsAPIContext } from './contexts';
88

99
export default function App() {
1010

11-
const [ buildings, setBuildings ] = useState<Buildings>([]);
12-
const [ roomDict, setRoomDict ] = useState<Room_Dictionary>({});
11+
const [ buildings, setBuildings ] = useState<Building[]>([]);
12+
const [ roomDict, setRoomDict ] = useState<StatusResponse>({});
1313
const handleRefresh = () => {};
1414

1515
useEffect(() => {

app/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Freerooms Mobile App
2+
3+
The Freerooms mobile app uses Expo
4+
5+
## Installation Guide
6+
7+
You can run the following command to install dependencies:
8+
```bash
9+
npm install
10+
```
11+
12+
In order to open the app on your phone, you will also need to install the [Expo Go app](https://expo.dev/client).
13+
14+
## Usage Guide
15+
You can run the app with the following command:
16+
17+
```bash
18+
npm run start
19+
```
20+
21+
This should generate a QR Code, which you scan with your phone to view the app. Make sure your phone is connected to the same WiFi as the machine that is running the server.

app/components/BuildingCard.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, useContext } from 'react';
1+
import React from 'react';
22
import {
33
StyleSheet,
44
Text,
@@ -8,8 +8,17 @@ import {
88
} from "react-native";
99

1010
import StatusIndicator from './StatusIndicator';
11+
import { BuildingStackScreenProps } from "../screens/types";
12+
import { StatusResponse } from "@common/types";
1113

12-
const BuildingCard = ({ nav, name, id, rooms }) => {
14+
interface BuildingCardProps {
15+
nav: BuildingStackScreenProps<"All Buildings">['navigation'],
16+
name: string,
17+
id: string,
18+
rooms: StatusResponse
19+
}
20+
21+
const BuildingCard: React.FC<BuildingCardProps> = ({ nav, name, id, rooms }) => {
1322

1423
const handlePress = (name: string, id : string ) => {
1524
nav.navigate("Building", { buildingName: name , buildingId : id });

app/components/RoomCard.tsx

+18-12
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,32 @@ import {
22
StyleSheet,
33
Text,
44
View,
5-
SafeAreaView,
6-
ScrollView,
75
Pressable,
86
} from "react-native";
97

108
import Ionicons from '@expo/vector-icons/Ionicons';
9+
import React from "react";
10+
import { RoomStatus } from "@common/types";
11+
import { BuildingStackScreenProps } from "../screens/types";
1112

13+
interface RoomCardProps {
14+
nav: BuildingStackScreenProps<"Building">['navigation'],
15+
roomNumber: string,
16+
status: RoomStatus
17+
}
1218

13-
const RoomCard = ({ nav, roomName, status, endtime }) => {
19+
const RoomCard: React.FC<RoomCardProps> = ({ nav, roomNumber, status }) => {
1420

1521
const handlePress = () => {
1622
nav.navigate("Room");
1723
}
1824

19-
const date = new Date(endtime);
20-
const hoursMinutes = date.toLocaleTimeString("en-AU", {
21-
hour: "numeric",
22-
minute: "2-digit",
23-
hour12: true,
24-
});
25+
const date = new Date(status.endtime);
26+
const hoursMinutes = date.toLocaleTimeString("en-AU", {
27+
hour: "numeric",
28+
minute: "2-digit",
29+
hour12: true,
30+
});
2531

2632
const roomStatusColor = {
2733
free: "#2AA300",
@@ -43,7 +49,7 @@ const RoomCard = ({ nav, roomName, status, endtime }) => {
4349
]}>
4450
<View>
4551
<Text style={styles.subHeading}>
46-
{ roomName }
52+
{ roomNumber }
4753
</Text>
4854
</View>
4955
<View style={styles.textContainer}>
@@ -52,9 +58,9 @@ const RoomCard = ({ nav, roomName, status, endtime }) => {
5258
paddingTop: 3.5,
5359
fontSize: 17,
5460
fontWeight: '600',
55-
color: roomStatusColor[status],
61+
color: roomStatusColor[status.status],
5662
}}>
57-
{roomStatusMessage[status]}
63+
{roomStatusMessage[status.status]}
5864
</Text>
5965
<Ionicons name="chevron-forward-outline" size={25} color='grey' />
6066
</View>

app/components/StatusDot.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { View, StyleSheet } from 'react-native';
2+
import React from "react";
23

4+
interface StatusDotProps {
5+
numRooms: number;
6+
}
37

4-
const StatusDot = ({numRooms}) => {
8+
const StatusDot: React.FC<StatusDotProps> = ({ numRooms }) => {
59
const bg = numRooms >= 5 ? "green" : numRooms !== 0 ? "orange" : "red";
610

711
return (

app/components/StatusIndicator.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { View, Text, StyleSheet } from 'react-native';
2-
import { Rooms } from '../services/freerooms_api/api_types';
32
import StatusDot from './StatusDot';
3+
import { BuildingStatus } from "@common/types";
4+
import React from "react";
45

5-
const StatusIndicator = ({rooms}) => {
6-
const roomsOfCurrBuilding:Rooms = rooms;
7-
const totalRooms:number = rooms ? Object.keys(roomsOfCurrBuilding).length : null;
8-
const freeRooms:number = rooms ? Object.values(roomsOfCurrBuilding).filter(x => x.status == "free" ).length : null;
6+
interface StatusIndicatorProps {
7+
rooms: BuildingStatus;
8+
}
9+
10+
const StatusIndicator: React.FC<StatusIndicatorProps> = ({rooms}) => {
11+
const totalRooms: number | null = rooms ? Object.keys(rooms).length : null;
12+
const freeRooms: number | null = rooms ? Object.values(rooms).filter(x => x.status == "free" ).length : null;
913

1014
return (
1115
<View style={styles.container}>

app/contexts.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { createContext } from "react";
2-
import type { Buildings, Room_Dictionary } from "./services/freerooms_api/api_types";
2+
import { Building, StatusResponse } from "@common/types";
33

44
type ContextType = {
5-
buildings : Buildings;
6-
rooms : Room_Dictionary,
5+
buildings : Building[];
6+
rooms : StatusResponse,
77
onRefresh : () => void;
88
}
99

app/screens/Buildings/building.tsx

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import React, { useState, useEffect, useContext } from 'react';
1+
import React, { useEffect, useContext } from 'react';
22
import {
33
StyleSheet,
44
Text,
55
View,
66
SafeAreaView,
7-
StatusBar,
87
ScrollView,
98
Pressable,
10-
Button,
119
} from "react-native";
1210

1311
import type { BuildingStackScreenProps } from '../types';
@@ -46,7 +44,13 @@ export default function Building({ route, navigation } : BuildingStackScreenProp
4644
<SafeAreaView style={ styles.container }>
4745
<ScrollView style={ styles.scrollView }>
4846
<View style={[styles.container, {paddingBottom: 20} ]}>
49-
{ Object.keys(roomsOfCurrBuilding).map( (roomId, index) => <RoomCard key={index} nav={navigation} roomName={roomId} {...roomsOfCurrBuilding[roomId]} /> )}
47+
{ Object.keys(roomsOfCurrBuilding).map( (roomNumber, index) =>
48+
<RoomCard
49+
key={index}
50+
nav={navigation}
51+
roomNumber={roomNumber}
52+
status={roomsOfCurrBuilding[roomNumber]}
53+
/> )}
5054
</View>
5155
</ScrollView>
5256
</SafeAreaView>

app/screens/Buildings/building_list.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, { useState, useEffect, useContext } from 'react';
1+
import React, { useEffect, useContext } from 'react';
22
import {
33
StyleSheet,
4-
Text,
54
View,
65
SafeAreaView,
76
ScrollView,
@@ -39,7 +38,13 @@ export default function BuildingList({ route, navigation } : BuildingStackScreen
3938
<View style={ styles.container }>
4039
<View style={ styles.textContainer }>
4140
</View>
42-
{ buildings.map((building, index) => <BuildingCard key={index} nav={navigation} rooms={rooms} {...building} /> )}
41+
{ buildings.map((building, index) =>
42+
<BuildingCard
43+
key={index}
44+
nav={navigation}
45+
rooms={rooms}
46+
{...building}
47+
/> )}
4348
</View>
4449
</ScrollView>
4550
</SafeAreaView>

app/services/freerooms_api/api_types.ts

-26
This file was deleted.

app/services/freerooms_api/config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
const config = {
3-
domain: "https://freerooms.csesoc.app",
3+
domain: "https://freerooms.staging.csesoc.unsw.edu.au",
44
endpoints: {
55
getBuildings: "/api/buildings",
66
getRooms: "/api/rooms/status",

app/services/freerooms_api/endpoints.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import type { Buildings, Room_Dictionary } from "./api_types";
1+
import { Building, BuildingsResponse, StatusResponse } from "@common/types";
22
import config from "./config";
33

44
const domain = config.domain;
5-
export async function getBuildings() : Promise<Buildings> {
5+
export async function getBuildings() : Promise<Building[]> {
66

77
const buildingsEndpoint = config.endpoints.getBuildings;
88

99
const url = `${domain}${buildingsEndpoint}`;
1010

11-
let buildings : Buildings = [];
11+
let buildings : Building[] = [];
1212
try {
1313
const response = await fetch(url);
14-
const data : { buildings : Buildings } = await response.json();
14+
const data : BuildingsResponse = await response.json();
1515
buildings = data.buildings;
1616
} catch {}
1717

1818
return buildings;
1919
}
2020

21-
export async function getRooms() : Promise<Room_Dictionary> {
21+
export async function getRooms() : Promise<StatusResponse> {
2222

2323
const roomsEndpoint = config.endpoints.getRooms;
2424
const url = `${domain}${roomsEndpoint}`;

0 commit comments

Comments
 (0)