Skip to content

Commit f8c1c3c

Browse files
Merge pull request #61 from MobilityData/feat/pre-launch-fixes
fix: pre launch fixes
2 parents 0baab3e + 987faff commit f8c1c3c

File tree

9 files changed

+36348
-21
lines changed

9 files changed

+36348
-21
lines changed

messages/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
"resultsFor": "{startResult}-{endResult} of {totalResults} results",
118118
"deprecated": "Deprecated",
119119
"searchPlaceholder": "Transit provider, feed name, or location",
120-
"noResults": "We're sorry, we found no search results for '{activeSearch}'.",
120+
"noResults": "We're sorry, we found no search results for ''{activeSearch}''.",
121121
"searchSuggestions": "Search suggestions: ",
122122
"searchTips": {
123123
"twoDigit": "Use the full English name of a location e.g \"France\" or \"New York City\"",

messages/fr.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
"resultsFor": "{startResult}-{endResult} of {totalResults} results",
118118
"deprecated": "Deprecated",
119119
"searchPlaceholder": "Transit provider, feed name, or location",
120-
"noResults": "We're sorry, we found no search results for '{activeSearch}'.",
120+
"noResults": "We're sorry, we found no search results for ''{activeSearch}''.",
121121
"searchSuggestions": "Search suggestions: ",
122122
"searchTips": {
123123
"twoDigit": "Use the full English name of a location e.g \"France\" or \"New York City\"",

src/app/api/revalidate/route.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,51 @@ const defaultRevalidateOptions: RevalidateBody = {
2222
feedIds: [],
2323
};
2424

25+
/**
26+
* GET handler for the Vercel cron job that revalidates all feed pages once a day.
27+
* Vercel automatically passes Authorization: Bearer <CRON_SECRET> with each invocation.
28+
* Configured in vercel.json under "crons" (schedule: 0 9 * * * = 4am EST / 9am UTC).
29+
*/
30+
export async function GET(req: Request): Promise<NextResponse> {
31+
const authHeader = req.headers.get('authorization');
32+
const cronSecret = process.env.CRON_SECRET;
33+
34+
if (cronSecret == null) {
35+
return NextResponse.json(
36+
{ ok: false, error: 'Server misconfigured: CRON_SECRET missing' },
37+
{ status: 500 },
38+
);
39+
}
40+
41+
if (authHeader !== `Bearer ${cronSecret}`) {
42+
return NextResponse.json(
43+
{ ok: false, error: 'Unauthorized' },
44+
{ status: 401 },
45+
);
46+
}
47+
48+
try {
49+
revalidateTag('guest-feeds', 'max');
50+
revalidatePath('/[locale]/feeds/[feedDataType]/[feedId]', 'layout');
51+
console.log(
52+
'[cron] revalidate /api/revalidate: all-feeds revalidation triggered',
53+
);
54+
return NextResponse.json({
55+
ok: true,
56+
message: 'All feeds revalidated successfully',
57+
});
58+
} catch (error) {
59+
console.error(
60+
'[cron] revalidate /api/revalidate: revalidation failed:',
61+
error,
62+
);
63+
return NextResponse.json(
64+
{ ok: false, error: 'Revalidation failed' },
65+
{ status: 500 },
66+
);
67+
}
68+
}
69+
2570
export async function POST(req: Request): Promise<NextResponse> {
2671
const expectedSecret = nonEmpty(process.env.REVALIDATE_SECRET);
2772
if (expectedSecret == null) {

src/app/components/Header.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ export default function DrawerAppBar(): React.ReactElement {
438438
<Button
439439
sx={{ fontFamily: fontFamily.secondary }}
440440
href={SIGN_IN_TARGET}
441+
component={Link}
441442
>
442443
Login
443444
</Button>

src/app/screens/Feed/Feed.functions.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Box, Typography } from '@mui/material';
33
import {
44
type GTFSFeedType,
55
type GBFSVersionType,
6+
type GBFSFeedType,
67
} from '../../services/feeds/utils';
78
import { type LatLngTuple } from 'leaflet';
89
import { type GeoJSONData, type GeoJSONDataGBFS } from '../../types';
@@ -192,36 +193,35 @@ export function computeBoundingBox(
192193
}
193194

194195
export const getBoundingBox = (
195-
feed: GTFSFeedType,
196+
feed: GTFSFeedType | GBFSFeedType ,
196197
): LatLngTuple[] | undefined => {
197-
if (feed == undefined || feed.data_type !== 'gtfs') {
198+
if (feed == undefined || feed.data_type === 'gtfs_rt') {
198199
return undefined;
199-
}
200-
const gtfsFeed: GTFSFeedType = feed;
200+
};
201201
if (
202-
gtfsFeed.bounding_box?.maximum_latitude == undefined ||
203-
gtfsFeed.bounding_box?.maximum_longitude == undefined ||
204-
gtfsFeed.bounding_box?.minimum_latitude == undefined ||
205-
gtfsFeed.bounding_box?.minimum_longitude == undefined
202+
feed.bounding_box?.maximum_latitude == undefined ||
203+
feed.bounding_box?.maximum_longitude == undefined ||
204+
feed.bounding_box?.minimum_latitude == undefined ||
205+
feed.bounding_box?.minimum_longitude == undefined
206206
) {
207207
return undefined;
208208
}
209209
return [
210210
[
211-
gtfsFeed.bounding_box.minimum_latitude,
212-
gtfsFeed.bounding_box.minimum_longitude,
211+
feed.bounding_box.minimum_latitude,
212+
feed.bounding_box.minimum_longitude,
213213
],
214214
[
215-
gtfsFeed.bounding_box.minimum_latitude,
216-
gtfsFeed.bounding_box.maximum_longitude,
215+
feed.bounding_box.minimum_latitude,
216+
feed.bounding_box.maximum_longitude,
217217
],
218218
[
219-
gtfsFeed.bounding_box.maximum_latitude,
220-
gtfsFeed.bounding_box.maximum_longitude,
219+
feed.bounding_box.maximum_latitude,
220+
feed.bounding_box.maximum_longitude,
221221
],
222222
[
223-
gtfsFeed.bounding_box.maximum_latitude,
224-
gtfsFeed.bounding_box.minimum_longitude,
223+
feed.bounding_box.maximum_latitude,
224+
feed.bounding_box.minimum_longitude,
225225
],
226226
];
227227
};

src/app/screens/Feed/FeedView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export default async function FeedView({
128128
? (feed as GBFSFeedType)?.source_info?.producer_url
129129
: undefined; // Simplified
130130

131-
const boundingBox = getBoundingBox(feed as GTFSFeedType);
131+
const boundingBox = getBoundingBox(feed);
132132

133133
let latestDataset: LatestDatasetFull;
134134
if (feed.data_type === 'gtfs') {

src/app/screens/Feed/components/FeedNavigationControls.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { Button, Grid, Typography } from '@mui/material';
44
import { ChevronLeft } from '@mui/icons-material';
55
import { useTranslations } from 'next-intl';
6-
import { useRouter } from '../../../../i18n/navigation';
6+
import { Link, useRouter } from '../../../../i18n/navigation';
77

88
interface Props {
99
feedDataType: string;
@@ -43,12 +43,18 @@ export default function FeedNavigationControls({
4343
},
4444
}}
4545
>
46-
<Button variant='text' href='/feeds' className='inline'>
46+
<Button
47+
variant='text'
48+
component={Link}
49+
href='/feeds'
50+
className='inline'
51+
>
4752
{t('feeds')}
4853
</Button>
4954
/
5055
<Button
5156
variant='text'
57+
component={Link}
5258
href={`/feeds?${feedDataType}=true`}
5359
className='inline'
5460
>

0 commit comments

Comments
 (0)