Skip to content

Commit f9b68b3

Browse files
authored
Version 0.44.1 (#1054)
- chore: disable error page for admin panel
2 parents c2075ea + 08280a9 commit f9b68b3

File tree

9 files changed

+60
-23
lines changed

9 files changed

+60
-23
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "conveniat27",
3-
"version": "0.44.0",
3+
"version": "0.44.1",
44
"description": "The official website of conveniat27",
55
"license": "MIT",
66
"author": "Cyrill Püntener v/o JPG (cyrill.puentener@cevi.ch)",

src/app/global-error.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,27 @@ const GlobalError: React.FC<{
2828
const [isRecovering, setIsRecovering] = useState(false);
2929

3030
useEffect(() => {
31+
// Check if the error is likely due to being offline (e.g., failed to load a JS chunk)
32+
const isOfflineError =
33+
!navigator.onLine ||
34+
error.name === 'ChunkLoadError' ||
35+
error.message.toLowerCase().includes('failed to fetch') ||
36+
error.message.toLowerCase().includes('network error');
37+
38+
// Completely disable global offline redirection for the Payload CMS admin panel.
39+
// Payload has its own offline handling and error boundaries.
40+
const isAdminPanel =
41+
typeof globalThis !== 'undefined' && globalThis.location.pathname.startsWith('/admin');
42+
3143
// In draft/preview mode, auto-reload instead of showing the error page.
3244
// This prevents the Payload CMS Live Preview iframe from getting stuck.
33-
if (isDraftOrPreviewMode()) {
45+
// We also do this for transient network errors in the admin panel to prevent the
46+
// root error boundary from permanently replacing the admin UI with a red error screen.
47+
const isTransientAdminError = isAdminPanel && isOfflineError;
48+
49+
if (isDraftOrPreviewMode() || isTransientAdminError) {
3450
console.warn(
35-
'[GlobalError] Transient error in draft/preview mode. Auto-reloading in 2s:',
51+
'[GlobalError] Transient error in admin/preview mode. Auto-reloading in 2s:',
3652
error.message,
3753
);
3854
setIsRecovering(true);
@@ -44,14 +60,7 @@ const GlobalError: React.FC<{
4460
};
4561
}
4662

47-
// Check if the error is likely due to being offline (e.g., failed to load a JS chunk)
48-
const isOfflineError =
49-
!navigator.onLine ||
50-
error.name === 'ChunkLoadError' ||
51-
error.message.toLowerCase().includes('failed to fetch') ||
52-
error.message.toLowerCase().includes('network error');
53-
54-
if (isOfflineError) {
63+
if (isOfflineError && !isAdminPanel) {
5564
console.error('[GlobalError] Network/Offline error detected:', {
5665
message: error.message,
5766
name: error.name,

src/features/map/api/map-router.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createTRPCRouter, trpcBaseProcedure } from '@/trpc/init';
2+
import { formatHexColor } from '@/utils/format-hex-color';
23
import config from '@payload-config';
34
import { getPayload } from 'payload';
45

@@ -36,7 +37,7 @@ export const mapRouter = createTRPCRouter({
3637
return {
3738
id: document_.id,
3839
title: document_.title,
39-
color: document_.color ?? '#47564c',
40+
color: formatHexColor(document_.color) ?? '#47564c',
4041
coordinates:
4142
rawCoords
4243
?.map((coord) => {

src/features/map/components/camp-map-component.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
import { resolveLinksInArray } from '@/features/payload-cms/payload-cms/utils/resolve-rich-text-links';
1111
import type { CampMapAnnotation as CampMapAnnotationPayloadDocumentType } from '@/features/payload-cms/payload-types';
1212
import type { Locale } from '@/types/types';
13+
import { formatHexColor } from '@/utils/format-hex-color';
1314
import config from '@payload-config';
1415
import { cacheLife, cacheTag } from 'next/cache';
1516
import { getPayload, type PaginatedDocs } from 'payload';
@@ -93,7 +94,7 @@ export const CampMapComponent: React.FC<{
9394
icon: document_.icon ?? 'MapPin',
9495
openingHours: document_.openingHours,
9596
images: document_.images ?? [],
96-
color: document_.color ?? '#47564c',
97+
color: formatHexColor(document_.color) ?? '#47564c',
9798
}) as CampMapAnnotationPoint,
9899
);
99100

@@ -117,7 +118,7 @@ export const CampMapComponent: React.FC<{
117118
icon: document_.icon ?? 'Tent',
118119
openingHours: isInteractive ? document_.openingHours : undefined,
119120
images: isInteractive ? (document_.images ?? []) : [],
120-
color: document_.color ?? '#47564c',
121+
color: formatHexColor(document_.color) ?? '#47564c',
121122
isInteractive,
122123
} as CampMapAnnotationPolygon;
123124
});

src/features/payload-cms/payload-cms/shared-fields/map-coordinates/map-coordinates-field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ const MapCoordinatesField: PointFieldClientComponent = ({ path }) => {
126126
const coordinates: [number, number][] = rawCoords.map((c) => [c.longitude, c.latitude]);
127127
polygonFeatures.push({
128128
type: 'Feature',
129-
properties: { color: item.color ?? '#78909c' },
129+
properties: { color: formatHexColor(item.color) ?? '#78909c' },
130130
geometry: {
131131
type: 'Polygon',
132132
coordinates: [coordinates],

src/features/payload-cms/payload-cms/shared-fields/map-polygon/map-polygon-field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ const MapPolygonField: FieldClientComponent = ({ path }) => {
300300
]);
301301
polygonFeatures.push({
302302
type: 'Feature',
303-
properties: { color: item.color ?? '#78909c' },
303+
properties: { color: formatHexColor(item.color) ?? '#78909c' },
304304
geometry: {
305305
type: 'Polygon',
306306
coordinates: [coordinates],

src/features/payload-cms/payload-cms/tasks/check-hitobito-approvals/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const checkHitobitoApprovalsTask: TaskConfig<'checkHitobitoApprovals'> =
3636
},
3737
schedule: [
3838
{
39-
cron: '0 */2 * * *', // Every 2 hours
39+
cron: '*/5 * * * *', // Every 5 minutes
4040
queue: DEFAULT_QUEUE,
4141
hooks: {
4242
beforeSchedule: async ({

src/features/service-worker/offline-support/fetch-handler.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,16 @@ export const handleFetchEvent =
290290
const isIngestRequest = url.pathname.startsWith('/ingest');
291291
const isTrpcRequest = url.pathname.startsWith('/api/trpc/');
292292

293-
// Bypass service worker entirely for admin panel, auth requests, ingest, and trpc requests
294-
const bypassSW =
295-
isPreviewRequest || isAdminPanel || isAuthRequest || isIngestRequest || isTrpcRequest;
293+
// avoid the service worker for admin panel and ingest requests
294+
if (isAdminPanel || isIngestRequest) {
295+
return;
296+
}
297+
298+
// Proxy bypass: We still want the SW to intercept these to provide the automatic
299+
// HTML retry wrapper on connection drops, but we skip cache lookup strategies.
300+
const bypassSWProxy = isPreviewRequest || isAuthRequest || isTrpcRequest;
296301

297-
if (bypassSW) {
302+
if (bypassSWProxy) {
298303
event.respondWith(
299304
(async (): Promise<Response> => {
300305
try {

src/providers/post-hog-provider.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,38 @@ export const PostHogProvider: React.FC<{ children: React.ReactNode }> = ({ child
8181
}
8282

8383
// Silent fail Payload Live Preview iframe cross-origin disconnects (noise during rapid save)
84+
// and generic background telemetry network errors from PostHog.
8485
if (
8586
message !== '' &&
86-
message.includes('blocked a frame with origin') &&
87+
(message.includes('blocked a frame with origin') ||
88+
message === 'network error' ||
89+
message.includes('failed to fetch')) &&
8790
(errorEvent.filename.includes('posthog') || errorEvent.filename === '')
8891
) {
8992
errorEvent.stopImmediatePropagation();
9093
errorEvent.preventDefault();
9194
}
9295
};
9396

94-
const handleUnhandledRejection = (): void => {};
97+
const handleUnhandledRejection = (event: PromiseRejectionEvent): void => {
98+
const reason = typeof event.reason === 'string' ? event.reason.toLowerCase() : '';
99+
const errorMessage = event.reason instanceof Error ? event.reason.message.toLowerCase() : '';
100+
const stack = event.reason instanceof Error ? (event.reason.stack ?? '').toLowerCase() : '';
101+
102+
const isNetworkNoise =
103+
reason.includes('network error') ||
104+
reason.includes('failed to fetch') ||
105+
errorMessage.includes('network error') ||
106+
errorMessage.includes('failed to fetch');
107+
108+
// Only suppress if the rejection originates from PostHog internals
109+
const isFromPostHog = stack.includes('posthog');
110+
111+
if (isNetworkNoise && isFromPostHog) {
112+
event.stopImmediatePropagation();
113+
event.preventDefault();
114+
}
115+
};
95116

96117
globalThis.addEventListener('error', handleError, { capture: true });
97118
globalThis.addEventListener('unhandledrejection', handleUnhandledRejection, { capture: true });

0 commit comments

Comments
 (0)