diff --git a/admin/src/all.dto.ts b/admin/src/all.dto.ts
index 5b490b39..e1c54b7a 100644
--- a/admin/src/all.dto.ts
+++ b/admin/src/all.dto.ts
@@ -29,6 +29,90 @@ export enum BearSlotDto {
ACCESSORY = 'ACCESSORY',
}
+export enum CampusEventCategoryDto {
+ SOCIAL = 'SOCIAL',
+ CULTURAL = 'CULTURAL',
+ ATHLETIC = 'ATHLETIC',
+ WELLNESS = 'WELLNESS',
+ ACADEMIC = 'ACADEMIC',
+ ARTS = 'ARTS',
+ CAREER = 'CAREER',
+ COMMUNITY = 'COMMUNITY',
+ OTHER = 'OTHER',
+}
+
+export enum EventSourceDto {
+ API_EVENTS = 'API_EVENTS',
+ ADMIN_CREATED = 'ADMIN_CREATED',
+ COMMUNITY_SUBMITTED = 'COMMUNITY_SUBMITTED',
+}
+
+export enum CheckInMethodDto {
+ LOCATION = 'LOCATION',
+ QR_CODE = 'QR_CODE',
+ EITHER = 'EITHER',
+}
+
+export enum CampusEventCategoriesDto {
+ SOCIAL = 'SOCIAL',
+ CULTURAL = 'CULTURAL',
+ ATHLETIC = 'ATHLETIC',
+ WELLNESS = 'WELLNESS',
+ ACADEMIC = 'ACADEMIC',
+ ARTS = 'ARTS',
+ CAREER = 'CAREER',
+ COMMUNITY = 'COMMUNITY',
+ OTHER = 'OTHER',
+}
+
+export enum CampusEventSourceDto {
+ API_EVENTS = 'API_EVENTS',
+ ADMIN_CREATED = 'ADMIN_CREATED',
+ COMMUNITY_SUBMITTED = 'COMMUNITY_SUBMITTED',
+}
+
+export enum CampusEventCheckInMethodDto {
+ LOCATION = 'LOCATION',
+ QR_CODE = 'QR_CODE',
+ EITHER = 'EITHER',
+}
+
+export enum RequestCampusEventsCategoriesDto {
+ SOCIAL = 'SOCIAL',
+ CULTURAL = 'CULTURAL',
+ ATHLETIC = 'ATHLETIC',
+ WELLNESS = 'WELLNESS',
+ ACADEMIC = 'ACADEMIC',
+ ARTS = 'ARTS',
+ CAREER = 'CAREER',
+ COMMUNITY = 'COMMUNITY',
+ OTHER = 'OTHER',
+}
+
+export enum UpsertCampusEventCategoriesDto {
+ SOCIAL = 'SOCIAL',
+ CULTURAL = 'CULTURAL',
+ ATHLETIC = 'ATHLETIC',
+ WELLNESS = 'WELLNESS',
+ ACADEMIC = 'ACADEMIC',
+ ARTS = 'ARTS',
+ CAREER = 'CAREER',
+ COMMUNITY = 'COMMUNITY',
+ OTHER = 'OTHER',
+}
+
+export enum UpsertCampusEventSourceDto {
+ API_EVENTS = 'API_EVENTS',
+ ADMIN_CREATED = 'ADMIN_CREATED',
+ COMMUNITY_SUBMITTED = 'COMMUNITY_SUBMITTED',
+}
+
+export enum UpsertCampusEventCheckInMethodDto {
+ LOCATION = 'LOCATION',
+ QR_CODE = 'QR_CODE',
+ EITHER = 'EITHER',
+}
+
export enum ChallengeLocationDto {
ENG_QUAD = 'ENG_QUAD',
ARTS_QUAD = 'ARTS_QUAD',
@@ -75,9 +159,13 @@ export enum EventCategoryDto {
FOOD = 'FOOD',
NATURE = 'NATURE',
HISTORICAL = 'HISTORICAL',
- CAFE = 'CAFE',
- DININGHALL = 'DININGHALL',
- DORM = 'DORM',
+ RESIDENTIAL = 'RESIDENTIAL',
+ LANDMARK = 'LANDMARK',
+ ARTS = 'ARTS',
+ ATHLETICS = 'ATHLETICS',
+ LIBRARY = 'LIBRARY',
+ ACADEMIC = 'ACADEMIC',
+ RECREATION = 'RECREATION',
}
export enum EventTimeLimitationDto {
@@ -244,6 +332,119 @@ export interface UpdatePurchaseResultDto {
itemId: string;
}
+export interface AdminBearItemDto {
+ id: string;
+ name?: string;
+ slot?: BearSlotDto;
+ cost?: number;
+ assetKey?: string;
+ mimeType?: string;
+ zIndex?: number;
+ isDefault?: boolean;
+}
+
+export interface UpdateBearItemDataDto {
+ bearItem: AdminBearItemDto;
+ deleted: boolean;
+}
+
+export interface RequestAllBearItemsDto {}
+
+export interface CampusEventDto {
+ id: string;
+ title: string;
+ description: string;
+ imageUrl?: string;
+ startTime: string;
+ endTime: string;
+ allDay: boolean;
+ locationName: string;
+ address?: string;
+ latitude: number;
+ longitude: number;
+ categories: CampusEventCategoriesDto[];
+ tags: string[];
+ source: CampusEventSourceDto;
+ externalUrl?: string;
+ organizerName?: string;
+ registrationUrl?: string;
+ checkInMethod: CampusEventCheckInMethodDto;
+ pointsForAttendance: number;
+ featured: boolean;
+ attendanceCount: number;
+ rsvpCount: number;
+}
+
+export interface RequestCampusEventsDto {
+ page: number;
+ limit: number;
+ dateFrom?: string;
+ dateTo?: string;
+ categories?: RequestCampusEventsCategoriesDto[];
+ search?: string;
+ featured?: boolean;
+}
+
+export interface CampusEventListDto {
+ events: CampusEventDto[];
+ total: number;
+ page: number;
+ limit: number;
+ totalPages: number;
+}
+
+export interface RequestCampusEventDetailsDto {
+ eventId: string;
+}
+
+export interface UpsertCampusEventDto {
+ id?: string;
+ title: string;
+ description: string;
+ imageUrl?: string;
+ startTime: string;
+ endTime: string;
+ allDay?: boolean;
+ locationName: string;
+ address?: string;
+ latitude: number;
+ longitude: number;
+ checkInRadius?: number;
+ categories: UpsertCampusEventCategoriesDto[];
+ tags: string[];
+ source: UpsertCampusEventSourceDto;
+ externalId?: string;
+ externalUrl?: string;
+ organizerName?: string;
+ organizerEmail?: string;
+ organizerId?: string;
+ checkInMethod?: UpsertCampusEventCheckInMethodDto;
+ pointsForAttendance?: number;
+ featured?: boolean;
+ registrationUrl?: string;
+}
+
+export interface DeleteCampusEventDto {
+ eventId: string;
+}
+
+export interface RsvpCampusEventDto {
+ eventId: string;
+}
+
+export interface UnRsvpCampusEventDto {
+ eventId: string;
+}
+
+export interface UpdateCampusEventDataDto {
+ event: CampusEventDto;
+ deleted: boolean;
+}
+
+export interface CampusEventListResponseDto {
+ list: CampusEventListDto;
+}
+
export interface CompletedChallengeDto {}
export interface ChallengeDto {
@@ -259,6 +460,8 @@ export interface ChallengeDto {
closeRadiusF?: number;
linkedEventId?: string;
timerLength?: number;
+ scheduledStartTime?: string;
+ scheduledEndTime?: string;
}
export interface RequestChallengeDataDto {
@@ -400,6 +603,7 @@ export interface PrevChallengeDto {
extensionsUsed?: number;
dateCompleted: string;
failed?: boolean;
+ dateExpired?: boolean;
}
export interface EventTrackerDto {
@@ -707,21 +911,3 @@ export interface JoinOrganizationDto {
export interface CompleteOnboardingDto {}
export interface ResetOnboardingDto {}
-
-export interface AdminBearItemDto {
- id: string;
- name?: string;
- slot?: BearSlotDto;
- cost?: number;
- assetKey?: string;
- mimeType?: string;
- zIndex?: number | null;
- isDefault?: boolean;
-}
-
-export interface UpdateBearItemDataDto {
- bearItem: AdminBearItemDto;
- deleted: boolean;
-}
-
-export interface RequestAllBearItemsDto {}
diff --git a/admin/src/components/ChallengeCardComponents.tsx b/admin/src/components/ChallengeCardComponents.tsx
index 3c87cef6..2359ac68 100644
--- a/admin/src/components/ChallengeCardComponents.tsx
+++ b/admin/src/components/ChallengeCardComponents.tsx
@@ -12,6 +12,7 @@ import {
OptionEntryForm,
MapEntryForm,
CheckboxNumberEntryForm,
+ CheckboxDateEntryForm,
AnswersEntryForm,
OptionWithCustomEntryForm,
} from './EntryModal';
@@ -223,6 +224,16 @@ export function makeChallengeForm(): EntryForm[] {
max: 3600,
numberLabel: 'Timer Length (seconds)',
},
+ {
+ name: 'Scheduled Start Time',
+ checked: false,
+ date: new Date(),
+ },
+ {
+ name: 'Scheduled End Time',
+ checked: false,
+ date: new Date(),
+ },
];
}
@@ -285,6 +296,20 @@ export function challengeToForm(challenge: ChallengeDto) {
max: 3600,
numberLabel: 'Timer Length (seconds)',
},
+ {
+ name: 'Scheduled Start Time',
+ checked: !!challenge.scheduledStartTime,
+ date: challenge.scheduledStartTime
+ ? new Date(challenge.scheduledStartTime)
+ : new Date(),
+ },
+ {
+ name: 'Scheduled End Time',
+ checked: !!challenge.scheduledEndTime,
+ date: challenge.scheduledEndTime
+ ? new Date(challenge.scheduledEndTime)
+ : new Date(),
+ },
];
}
@@ -294,6 +319,8 @@ export function challengeFromForm(
id: string,
): ChallengeDto {
const timerForm = form[8] as CheckboxNumberEntryForm;
+ const startForm = form[9] as CheckboxDateEntryForm;
+ const endForm = form[10] as CheckboxDateEntryForm;
return {
id,
name: (form[2] as FreeEntryForm).value,
@@ -307,6 +334,10 @@ export function challengeFromForm(
closeRadiusF: (form[7] as NumberEntryForm).value,
linkedEventId: eventId,
timerLength: timerForm.checked ? timerForm.value : undefined,
+ scheduledStartTime: startForm.checked
+ ? startForm.date.toISOString()
+ : undefined,
+ scheduledEndTime: endForm.checked ? endForm.date.toISOString() : undefined,
};
}
@@ -412,6 +443,14 @@ export function ChallengeCard(props: {
? `${Math.floor(props.challenge.timerLength / 60)}m ${props.challenge.timerLength % 60}s`
: 'None'}
+
+ Scheduled:{' '}
+
+ {props.challenge.scheduledStartTime ||
+ props.challenge.scheduledEndTime
+ ? `${props.challenge.scheduledStartTime ? new Date(props.challenge.scheduledStartTime).toLocaleString() : '—'} to ${props.challenge.scheduledEndTime ? new Date(props.challenge.scheduledEndTime).toLocaleString() : '—'}`
+ : 'None'}
+
UP
diff --git a/admin/src/components/Challenges.tsx b/admin/src/components/Challenges.tsx
index 93166685..a97340ac 100644
--- a/admin/src/components/Challenges.tsx
+++ b/admin/src/components/Challenges.tsx
@@ -45,9 +45,13 @@ const eventCategoryOptions = [
'FOOD',
'NATURE',
'HISTORICAL',
- 'CAFE',
- 'DININGHALL',
- 'DORM',
+ 'RESIDENTIAL',
+ 'LANDMARK',
+ 'ARTS',
+ 'ATHLETICS',
+ 'LIBRARY',
+ 'ACADEMIC',
+ 'RECREATION',
];
// Combined form indices:
diff --git a/admin/src/components/EntryModal.tsx b/admin/src/components/EntryModal.tsx
index 0c63d374..98ecf35e 100644
--- a/admin/src/components/EntryModal.tsx
+++ b/admin/src/components/EntryModal.tsx
@@ -60,6 +60,12 @@ export type AnswersEntryForm = {
maxAnswers: number;
};
+export type CheckboxDateEntryForm = {
+ name: string;
+ checked: boolean;
+ date: Date;
+};
+
export type OptionWithCustomEntryForm = {
name: string;
value: number;
@@ -76,7 +82,8 @@ export type EntryForm =
| DateEntryForm
| CheckboxNumberEntryForm
| AnswersEntryForm
- | OptionWithCustomEntryForm;
+ | OptionWithCustomEntryForm
+ | CheckboxDateEntryForm;
const EntryBox = styled.div`
margin-bottom: 12px;
@@ -256,6 +263,46 @@ function CheckboxNumberEntryFormBox(props: { form: CheckboxNumberEntryForm }) {
);
}
+function CheckboxDateEntryFormBox(props: { form: CheckboxDateEntryForm }) {
+ const [checked, setChecked] = useState(props.form.checked);
+ const [val, setVal] = useState('');
+
+ useEffect(() => {
+ setChecked(props.form.checked);
+ setVal(props.form.date.toISOString().slice(0, 16));
+ }, [props.form]);
+
+ return (
+ <>
+
+
+
+ {checked && (
+
+ {
+ setVal(e.target.value);
+ props.form.date = new Date(e.target.value);
+ }}
+ />
+
+ )}
+ >
+ );
+}
+
const MapBox = styled.div`
width: 100%;
height: 300px;
@@ -270,9 +317,81 @@ const mapContainerStyle = {
height: '300px',
};
+type FrontendConfigResponse = {
+ googleMapsApiKey?: string;
+};
+
function MapEntryFormBox(props: {
form: MapEntryForm;
allForms?: EntryForm[];
+}) {
+ const [googleMapsApiKey, setGoogleMapsApiKey] = useState(
+ process.env.REACT_APP_GOOGLE_MAPS_API_KEY || '',
+ );
+ const [hasLoadedConfig, setHasLoadedConfig] = useState(
+ Boolean(process.env.REACT_APP_GOOGLE_MAPS_API_KEY),
+ );
+
+ useEffect(() => {
+ if (googleMapsApiKey) {
+ setHasLoadedConfig(true);
+ return;
+ }
+
+ let isCancelled = false;
+
+ fetch('/frontend-config')
+ .then(async response => {
+ if (!response.ok) {
+ throw new Error(`Failed to load config: ${response.status}`);
+ }
+
+ const config = (await response.json()) as FrontendConfigResponse;
+
+ if (isCancelled) {
+ return;
+ }
+
+ setGoogleMapsApiKey(config.googleMapsApiKey || '');
+ setHasLoadedConfig(true);
+ })
+ .catch(() => {
+ if (!isCancelled) {
+ setHasLoadedConfig(true);
+ }
+ });
+
+ return () => {
+ isCancelled = true;
+ };
+ }, [googleMapsApiKey]);
+
+ if (!hasLoadedConfig) {
+ return Loading map configuration...;
+ }
+
+ if (!googleMapsApiKey) {
+ return (
+
+ Google Maps is unavailable. Set `REACT_APP_GOOGLE_MAPS_API_KEY` in the
+ running server environment.
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+function LoadedMapEntryFormBox(props: {
+ form: MapEntryForm;
+ allForms?: EntryForm[];
+ googleMapsApiKey: string;
}) {
const [lat, setLat] = useState(props.form.latitude);
const [lng, setLng] = useState(props.form.longitude);
@@ -282,8 +401,8 @@ function MapEntryFormBox(props: {
lng: props.form.longitude,
});
- const { isLoaded } = useJsApiLoader({
- googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY || '',
+ const { isLoaded, loadError } = useJsApiLoader({
+ googleMapsApiKey: props.googleMapsApiKey,
});
// Derive radii from form so map updates when Awarding/Close Distance fields change
@@ -343,6 +462,15 @@ function MapEntryFormBox(props: {
}
};
+ if (loadError) {
+ return (
+
+ Unable to load Google Maps. Verify the API key, referrer restrictions,
+ and that the Maps JavaScript API is enabled.
+
+ );
+ }
+
if (!isLoaded) return Loading map...;
return (
@@ -607,6 +735,8 @@ export function EntryModal(props: {
return ;
} else if ('characterLimit' in form) {
return ;
+ } else if ('date' in form && 'checked' in form) {
+ return ;
} else if ('checked' in form) {
return ;
} else if ('min' in form) {
diff --git a/admin/src/components/Journeys.tsx b/admin/src/components/Journeys.tsx
index 63abbcba..09154e30 100644
--- a/admin/src/components/Journeys.tsx
+++ b/admin/src/components/Journeys.tsx
@@ -48,9 +48,13 @@ const categoryOptions = [
'FOOD',
'NATURE',
'HISTORICAL',
- 'CAFE',
- 'DININGHALL',
- 'DORM',
+ 'RESIDENTIAL',
+ 'LANDMARK',
+ 'ARTS',
+ 'ATHLETICS',
+ 'LIBRARY',
+ 'ACADEMIC',
+ 'RECREATION',
];
// Event form helpers
diff --git a/admin/src/components/ServerApi.tsx b/admin/src/components/ServerApi.tsx
index d9af8b27..cb57926f 100644
--- a/admin/src/components/ServerApi.tsx
+++ b/admin/src/components/ServerApi.tsx
@@ -55,6 +55,64 @@ export class ServerApi {
return this.send('equipBearItem', data) as Promise;
}
+ requestAllBearItems(data: dto.RequestAllBearItemsDto) {
+ return this.send('requestAllBearItems', data) as Promise<
+ number | undefined
+ >;
+ }
+
+ updateBearItemData(data: dto.UpdateBearItemDataDto) {
+ return this.send('updateBearItemData', data) as Promise;
+ }
+
+ requestCampusEvents(data: dto.RequestCampusEventsDto) {
+ return this.send('requestCampusEvents', data) as Promise<
+ number | undefined
+ >;
+ }
+
+ requestCampusEventDetails(data: dto.RequestCampusEventDetailsDto) {
+ return this.send('requestCampusEventDetails', data) as Promise<
+ string | undefined
+ >;
+ }
+
+ requestAllCampusEvents(data: dto.RequestCampusEventsDto) {
+ return this.send('requestAllCampusEvents', data) as Promise<
+ number | undefined
+ >;
+ }
+
+ createCampusEvent(data: dto.UpsertCampusEventDto) {
+ return this.send('createCampusEvent', data) as Promise;
+ }
+
+ updateCampusEvent(data: dto.UpsertCampusEventDto) {
+ return this.send('updateCampusEvent', data) as Promise;
+ }
+
+ deleteCampusEvent(data: dto.DeleteCampusEventDto) {
+ return this.send('deleteCampusEvent', data) as Promise;
+ }
+
+ rsvpCampusEvent(data: dto.RsvpCampusEventDto) {
+ return this.send('rsvpCampusEvent', data) as Promise;
+ }
+
+ unRsvpCampusEvent(data: dto.UnRsvpCampusEventDto) {
+ return this.send('unRsvpCampusEvent', data) as Promise;
+ }
+
+ requestAvailableChallenges(data: dto.RequestAvailableChallengesDto) {
+ return this.send('requestAvailableChallenges', data) as Promise<
+ any | undefined
+ >;
+ }
+
+ setCurrentChallenge(data: dto.SetCurrentChallengeDto) {
+ return this.send('setCurrentChallenge', data) as Promise;
+ }
+
requestChallengeData(data: dto.RequestChallengeDataDto) {
return this.send('requestChallengeData', data) as Promise<
number | undefined
@@ -119,6 +177,14 @@ export class ServerApi {
return this.send('updateEventData', data) as Promise;
}
+ triggerEventSync(data: dto.TriggerEventSyncDto) {
+ return this.send('triggerEventSync', data) as Promise;
+ }
+
+ requestEventSyncStatus() {
+ return this.send('requestEventSyncStatus', {}) as Promise;
+ }
+
submitFeedback(data: dto.SubmitFeedbackDto) {
return this.send('submitFeedback', data) as Promise;
}
@@ -155,6 +221,14 @@ export class ServerApi {
return this.send('updateFcmToken', data) as Promise;
}
+ sendNotification(data: dto.SendNotificationDto) {
+ return this.send('sendNotification', data) as Promise;
+ }
+
+ removeFcmToken() {
+ return this.send('removeFcmToken', {}) as Promise;
+ }
+
requestOrganizationData(data: dto.RequestOrganizationDataDto) {
return this.send('requestOrganizationData', data) as Promise<
number | undefined
@@ -259,21 +333,6 @@ export class ServerApi {
return this.send('closeAccount', data) as Promise;
}
- requestAllBearItems(data: dto.RequestAllBearItemsDto) {
- return this.send('requestAllBearItems', data) as Promise<
- number | undefined
- >;
- }
-
- updateBearItemData(data: dto.UpdateBearItemDataDto) {
- return this.send('updateBearItemData', data) as Promise;
- }
-
- onUpdateBearItemData(callback: (data: dto.UpdateBearItemDataDto) => void) {
- this.socket.removeAllListeners('updateBearItemData');
- this.socket.on('updateBearItemData', data => callback(data));
- }
-
onUpdateUserData(callback: (data: dto.UpdateUserDataDto) => void) {
this.socket.removeAllListeners('updateUserData');
this.socket.on('updateUserData', data => callback(data));
@@ -347,6 +406,11 @@ export class ServerApi {
this.socket.on('updateBearItemsData', data => callback(data));
}
+ onUpdateBearItemData(callback: (data: dto.UpdateBearItemDataDto) => void) {
+ this.socket.removeAllListeners('updateBearItemData');
+ this.socket.on('updateBearItemData', data => callback(data));
+ }
+
onUpdateUserInventoryData(
callback: (data: dto.UpdateUserInventoryDataDto) => void,
) {
@@ -424,4 +488,16 @@ export class ServerApi {
this.socket.removeAllListeners('updateFeedbackData');
this.socket.on('updateFeedbackData', data => callback(data));
}
+
+ onUpdateCampusEventData(
+ callback: (data: dto.UpdateCampusEventDataDto) => void,
+ ) {
+ this.socket.removeAllListeners('updateCampusEventData');
+ this.socket.on('updateCampusEventData', data => callback(data));
+ }
+
+ onCampusEventList(callback: (data: dto.CampusEventListResponseDto) => void) {
+ this.socket.removeAllListeners('campusEventList');
+ this.socket.on('campusEventList', data => callback(data));
+ }
}
diff --git a/game/android/app/build.gradle b/game/android/app/build.gradle
index eae29aae..1fa7ea85 100644
--- a/game/android/app/build.gradle
+++ b/game/android/app/build.gradle
@@ -43,7 +43,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId 'com.cornellgo.CornellGOApp'
- minSdkVersion flutter.minSdkVersion
+ minSdkVersion 23
targetSdkVersion 35
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/game/assets/buildabear/eyes/><.png b/game/assets/buildabear/eyes/greaterthan_lessthan.png
similarity index 100%
rename from game/assets/buildabear/eyes/><.png
rename to game/assets/buildabear/eyes/greaterthan_lessthan.png
diff --git a/game/assets/buildabear/eyes/squinty_eyes.png b/game/assets/buildabear/eyes/squinty_eyes.png
new file mode 100644
index 00000000..89d10de5
Binary files /dev/null and b/game/assets/buildabear/eyes/squinty_eyes.png differ
diff --git a/game/assets/icons/pluscircle_red.svg b/game/assets/icons/pluscircle_red.svg
new file mode 100644
index 00000000..d09c6eaf
--- /dev/null
+++ b/game/assets/icons/pluscircle_red.svg
@@ -0,0 +1,4 @@
+
diff --git a/game/ios/Podfile.lock b/game/ios/Podfile.lock
index 76700fce..cd48c01c 100644
--- a/game/ios/Podfile.lock
+++ b/game/ios/Podfile.lock
@@ -270,7 +270,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
- device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
+ device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
firebase_core: 995454a784ff288be5689b796deb9e9fa3601818
firebase_messaging: f4a41dd102ac18b840eba3f39d67e77922d3f707
diff --git a/game/lib/api/game_client_api.dart b/game/lib/api/game_client_api.dart
index 99a14b22..890905c1 100644
--- a/game/lib/api/game_client_api.dart
+++ b/game/lib/api/game_client_api.dart
@@ -73,6 +73,11 @@ class GameClientApi {
Stream get updateBearItemsDataStream =>
_updateBearItemsDataController.stream;
+ final _updateBearItemDataController =
+ StreamController.broadcast(sync: true);
+ Stream get updateBearItemDataStream =>
+ _updateBearItemDataController.stream;
+
final _updateUserInventoryDataController =
StreamController.broadcast(sync: true);
Stream get updateUserInventoryDataStream =>
@@ -136,6 +141,21 @@ class GameClientApi {
Stream get quizProgressStream =>
_quizProgressController.stream;
+ final _updateFeedbackDataController =
+ StreamController.broadcast(sync: true);
+ Stream get updateFeedbackDataStream =>
+ _updateFeedbackDataController.stream;
+
+ final _updateCampusEventDataController =
+ StreamController.broadcast(sync: true);
+ Stream get updateCampusEventDataStream =>
+ _updateCampusEventDataController.stream;
+
+ final _campusEventListController =
+ StreamController.broadcast(sync: true);
+ Stream get campusEventListStream =>
+ _campusEventListController.stream;
+
final _reconnectedController = StreamController.broadcast(sync: true);
Stream get reconnectedStream => _reconnectedController.stream;
@@ -218,6 +238,11 @@ class GameClientApi {
(data) => _updateBearItemsDataController
.add(UpdateBearItemsDataDto.fromJson(data)));
+ sock.on(
+ "updateBearItemData",
+ (data) => _updateBearItemDataController
+ .add(UpdateBearItemDataDto.fromJson(data)));
+
sock.on(
"updateUserInventoryData",
(data) => _updateUserInventoryDataController
@@ -271,6 +296,21 @@ class GameClientApi {
sock.on("quizProgress",
(data) => _quizProgressController.add(QuizProgressDto.fromJson(data)));
+ sock.on(
+ "updateFeedbackData",
+ (data) => _updateFeedbackDataController
+ .add(UpdateFeedbackDataDto.fromJson(data)));
+
+ sock.on(
+ "updateCampusEventData",
+ (data) => _updateCampusEventDataController
+ .add(UpdateCampusEventDataDto.fromJson(data)));
+
+ sock.on(
+ "campusEventList",
+ (data) => _campusEventListController
+ .add(CampusEventListResponseDto.fromJson(data)));
+
_connectedController.add(true);
}
diff --git a/game/lib/api/game_client_dto.dart b/game/lib/api/game_client_dto.dart
index b355f7df..ae0a9ba7 100644
--- a/game/lib/api/game_client_dto.dart
+++ b/game/lib/api/game_client_dto.dart
@@ -29,6 +29,90 @@ enum BearSlotDto {
ACCESSORY,
}
+enum CampusEventCategoryDto {
+ SOCIAL,
+ CULTURAL,
+ ATHLETIC,
+ WELLNESS,
+ ACADEMIC,
+ ARTS,
+ CAREER,
+ COMMUNITY,
+ OTHER,
+}
+
+enum EventSourceDto {
+ API_EVENTS,
+ ADMIN_CREATED,
+ COMMUNITY_SUBMITTED,
+}
+
+enum CheckInMethodDto {
+ LOCATION,
+ QR_CODE,
+ EITHER,
+}
+
+enum CampusEventCategoriesDto {
+ SOCIAL,
+ CULTURAL,
+ ATHLETIC,
+ WELLNESS,
+ ACADEMIC,
+ ARTS,
+ CAREER,
+ COMMUNITY,
+ OTHER,
+}
+
+enum CampusEventSourceDto {
+ API_EVENTS,
+ ADMIN_CREATED,
+ COMMUNITY_SUBMITTED,
+}
+
+enum CampusEventCheckInMethodDto {
+ LOCATION,
+ QR_CODE,
+ EITHER,
+}
+
+enum RequestCampusEventsCategoriesDto {
+ SOCIAL,
+ CULTURAL,
+ ATHLETIC,
+ WELLNESS,
+ ACADEMIC,
+ ARTS,
+ CAREER,
+ COMMUNITY,
+ OTHER,
+}
+
+enum UpsertCampusEventCategoriesDto {
+ SOCIAL,
+ CULTURAL,
+ ATHLETIC,
+ WELLNESS,
+ ACADEMIC,
+ ARTS,
+ CAREER,
+ COMMUNITY,
+ OTHER,
+}
+
+enum UpsertCampusEventSourceDto {
+ API_EVENTS,
+ ADMIN_CREATED,
+ COMMUNITY_SUBMITTED,
+}
+
+enum UpsertCampusEventCheckInMethodDto {
+ LOCATION,
+ QR_CODE,
+ EITHER,
+}
+
enum ChallengeLocationDto {
ENG_QUAD,
ARTS_QUAD,
@@ -75,9 +159,13 @@ enum EventCategoryDto {
FOOD,
NATURE,
HISTORICAL,
- CAFE,
- DININGHALL,
- DORM,
+ RESIDENTIAL,
+ LANDMARK,
+ ARTS,
+ ATHLETICS,
+ LIBRARY,
+ ACADEMIC,
+ RECREATION,
}
enum EventTimeLimitationDto {
@@ -694,172 +782,874 @@ class RequestBearItemsDto {
return fields;
}
- RequestBearItemsDto.fromJson(Map fields) {
- slot = fields.containsKey('slot')
- ? (BearSlotDto.values.byName(fields['slot']))
+ RequestBearItemsDto.fromJson(Map fields) {
+ slot = fields.containsKey('slot')
+ ? (BearSlotDto.values.byName(fields['slot']))
+ : null;
+ }
+
+ void partialUpdate(RequestBearItemsDto other) {
+ slot = other.slot == null ? slot : other.slot;
+ }
+
+ RequestBearItemsDto({
+ this.slot,
+ });
+
+ late BearSlotDto? slot;
+}
+
+class RequestUserInventoryDto {
+ Map toJson() {
+ Map fields = {};
+ return fields;
+ }
+
+ RequestUserInventoryDto.fromJson(Map fields) {}
+
+ void partialUpdate(RequestUserInventoryDto other) {}
+
+ RequestUserInventoryDto();
+}
+
+class RequestUserBearLoadoutDto {
+ Map toJson() {
+ Map fields = {};
+ return fields;
+ }
+
+ RequestUserBearLoadoutDto.fromJson(Map fields) {}
+
+ void partialUpdate(RequestUserBearLoadoutDto other) {}
+
+ RequestUserBearLoadoutDto();
+}
+
+class UpdateBearItemsDataDto {
+ Map toJson() {
+ Map fields = {};
+ fields['items'] = items!
+ .map