Add initial region loading for supported systems

Expose an initialRegion field on the System GraphQL type so the app can
display the correct campus area on first load instead of a zoomed-out
default map view. Chapman University is configured with coordinates
centered on campus.

https://claude.ai/code/session_0162emnCi1KxW5FkTNn2ZrvH
This commit is contained in:
Claude
2026-03-23 22:02:42 +00:00
parent 690b2e1559
commit 946f8dd342
7 changed files with 74 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ scalar DateTime
type System { type System {
id: ID! id: ID!
name: String! name: String!
initialRegion: Region
routes: [Route!] routes: [Route!]
route(id: ID): Route route(id: ID): Route
stops: [Stop!] stops: [Stop!]
@@ -16,6 +17,13 @@ type System {
parkingSystem: ParkingSystem parkingSystem: ParkingSystem
} }
type Region {
latitude: Float!
longitude: Float!
latitudeDelta: Float!
longitudeDelta: Float!
}
type ParkingSystem { type ParkingSystem {
systemId: ID! systemId: ID!
parkingStructures: [ParkingStructure!] parkingStructures: [ParkingStructure!]

View File

@@ -19,6 +19,7 @@ import { InMemoryExternalSourceETARepository } from "../repositories/shuttle/eta
import { ETAGetterRepository } from "../repositories/shuttle/eta/ETAGetterRepository"; import { ETAGetterRepository } from "../repositories/shuttle/eta/ETAGetterRepository";
import { InMemorySelfUpdatingETARepository } from "../repositories/shuttle/eta/InMemorySelfUpdatingETARepository"; import { InMemorySelfUpdatingETARepository } from "../repositories/shuttle/eta/InMemorySelfUpdatingETARepository";
import { BaseInMemoryETARepository } from "../repositories/shuttle/eta/BaseInMemoryETARepository"; import { BaseInMemoryETARepository } from "../repositories/shuttle/eta/BaseInMemoryETARepository";
import { IRegion } from "./SharedEntities";
export interface InterchangeSystemBuilderArguments { export interface InterchangeSystemBuilderArguments {
name: string; name: string;
@@ -49,6 +50,12 @@ export interface InterchangeSystemBuilderArguments {
* at a stop, in latitude/longitude degrees. * at a stop, in latitude/longitude degrees.
*/ */
shuttleStopArrivalDegreeDelta: number; shuttleStopArrivalDegreeDelta: number;
/**
* The initial map region to display when the app first loads
* this system. Represents a center coordinate and span.
*/
initialRegion?: IRegion;
} }
export class InterchangeSystem { export class InterchangeSystem {
@@ -62,6 +69,7 @@ export class InterchangeSystem {
public notificationRepository: NotificationRepository, public notificationRepository: NotificationRepository,
public parkingTimedDataLoader: TimedApiBasedRepositoryLoader | null, public parkingTimedDataLoader: TimedApiBasedRepositoryLoader | null,
public parkingRepository: ParkingGetterSetterRepository | null, public parkingRepository: ParkingGetterSetterRepository | null,
public initialRegion: IRegion | null,
) { ) {
} }
@@ -96,6 +104,7 @@ export class InterchangeSystem {
notificationRepository, notificationRepository,
timedParkingLoader, timedParkingLoader,
parkingRepository, parkingRepository,
args.initialRegion ?? null,
); );
} }
@@ -205,6 +214,7 @@ export class InterchangeSystem {
notificationRepository, notificationRepository,
timedParkingLoader, timedParkingLoader,
parkingRepository, parkingRepository,
args.initialRegion ?? null,
); );
} }

View File

@@ -11,3 +11,10 @@ export interface ICoordinates {
longitude: number; longitude: number;
} }
export interface IRegion {
latitude: number;
longitude: number;
latitudeDelta: number;
longitudeDelta: number;
}

View File

@@ -25,6 +25,12 @@ const supportedSystems: InterchangeSystemBuilderArguments[] = [
name: "Chapman University", name: "Chapman University",
useSelfUpdatingEtas: true, useSelfUpdatingEtas: true,
shuttleStopArrivalDegreeDelta: 0.001, shuttleStopArrivalDegreeDelta: 0.001,
initialRegion: {
latitude: 33.7937,
longitude: -117.8531,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
},
} }
] ]

View File

@@ -83,6 +83,14 @@ export const SystemResolvers: Resolvers<ServerContext> = {
const shuttles = await system.shuttleRepository.getShuttles(); const shuttles = await system.shuttleRepository.getShuttles();
return shuttles.slice().sort((a, b) => a.name.localeCompare(b.name)); return shuttles.slice().sort((a, b) => a.name.localeCompare(b.name));
}, },
initialRegion: async (parent, _args, contextValue, _info) => {
const system = contextValue.findSystemById(parent.id);
if (!system) {
return null;
}
return system.initialRegion;
},
parkingSystem: async (parent, _args, contextValue, _info) => { parkingSystem: async (parent, _args, contextValue, _info) => {
const system = contextValue.findSystemById(parent.id); const system = contextValue.findSystemById(parent.id);
if (!system) { if (!system) {

View File

@@ -35,6 +35,35 @@ describe("SystemResolvers", () => {
}); });
} }
describe("initialRegion", () => {
const query = `
query GetSystemInitialRegion($systemId: ID!) {
system(id: $systemId) {
initialRegion {
latitude
longitude
latitudeDelta
longitudeDelta
}
}
}
`;
it("returns the initial region for the system", async () => {
const response = await getResponseFromQueryNeedingSystemId(query);
assert(response.body.kind === "single");
expect(response.body.singleResult.errors).toBeUndefined();
const initialRegion = (response.body.singleResult.data as any).system.initialRegion;
expect(initialRegion).toEqual({
latitude: 33.7937,
longitude: -117.8531,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
});
});
});
describe("routes", () => { describe("routes", () => {
const query = ` const query = `
query GetSystemRoutes($systemId: ID!) { query GetSystemRoutes($systemId: ID!) {

View File

@@ -26,6 +26,12 @@ const systemInfoForTesting: InterchangeSystemBuilderArguments = {
parkingSystemId: ChapmanApiBasedParkingRepositoryLoader.id, parkingSystemId: ChapmanApiBasedParkingRepositoryLoader.id,
useSelfUpdatingEtas: false, useSelfUpdatingEtas: false,
shuttleStopArrivalDegreeDelta: 0.001, shuttleStopArrivalDegreeDelta: 0.001,
initialRegion: {
latitude: 33.7937,
longitude: -117.8531,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
},
}; };
export function buildSystemForTesting() { export function buildSystemForTesting() {