Wall of People Groups: say so when the live API cannot be reached, and stop a render error
With pray.doxa.life unreachable (offline, or a local dev server whose 127.0.0.1 origin the API
refuses by CORS) the wall sat at "0 Groups Loaded" with nothing explaining why, and logged
"Cannot read properties of undefined (reading 'length')". That error was not the fetch at all:
SourceSelector's template read `sources`, which does not exist (its computed is
availableSources), so it threw on every render, online as well.
- SourceSelector: availableSources.
- PeopleGroupsWall: when nothing loaded and the store holds an error, an in-wall notice says
what failed and offers Try again (inside the wall, never position:fixed over a host page).
- The store logs the network failure as a warning: it is an expected state now shown on screen.
Measured with every pray.doxa.life request aborted: the TypeError is gone, the notice renders,
and the only console line left is the browser's own "Failed to load resource". Unblocking and
pressing Try again loads 2107 groups. Live (unblocked): 2107 groups, 0 console errors.
This commit is contained in:
parent
5e7ad5a409
commit
e31738762c
4 changed files with 42 additions and 2 deletions
|
|
@ -18,6 +18,16 @@
|
|||
<div class="spinner"></div>
|
||||
<p>Loading people groups...</p>
|
||||
</div>
|
||||
|
||||
<!-- OFFLINE / BLOCKED: the live API could not be reached. Measured on a local dev server,
|
||||
where pray.doxa.life refuses a 127.0.0.1 origin (CORS): the wall used to sit at
|
||||
"0 Groups Loaded" with nothing saying why. Say what failed and offer a retry. -->
|
||||
<div v-else-if="loadError && totalGroups === 0" class="wall-offline" role="status">
|
||||
<p class="wall-offline-title">The live prayer data could not be reached.</p>
|
||||
<p>The wall reads its people groups from pray.doxa.life. You may be offline, or, on a
|
||||
local development server, the API may not allow this page's address.</p>
|
||||
<button type="button" class="control-btn" @click="fetchData">Try again</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
|
@ -50,6 +60,10 @@ export default {
|
|||
|
||||
peopleGroups() {
|
||||
return this.$store?.peopleGroups || [];
|
||||
},
|
||||
|
||||
loadError() {
|
||||
return this.$store?.error || null;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<div v-if="sources.length > 1">
|
||||
<!-- availableSources, the computed below: the template read an undefined `sources`, so this
|
||||
threw "reading 'length'" on EVERY render, online or not (Vue logs it; nothing crashes) -->
|
||||
<div v-if="availableSources.length > 1">
|
||||
<div class="source-selector">
|
||||
<div class="source-header">
|
||||
<h3>📊 Data Source</h3>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,9 @@ export const usePeopleGroupsStore = (pinia) => {
|
|||
console.log('First 3 groups:', this.peopleGroups.slice(0, 3));
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error fetching people groups from ${this.dataSource}:`, error);
|
||||
// warn, not error: the wall now SAYS so on screen (PeopleGroupsWall's offline notice)
|
||||
// and offers a retry; an unreachable API is an expected state, not a crash.
|
||||
console.warn(`Could not fetch people groups from ${this.dataSource}:`, error && error.message);
|
||||
this.error = error.message;
|
||||
this.peopleGroups = [];
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -116,6 +116,28 @@ body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Offline / blocked notice: the live API could not be reached. Sits over the empty canvas,
|
||||
inside the wall (not position:fixed), so an embedded wall never covers its host page. */
|
||||
.wall-container { position: relative; }
|
||||
.wall-offline {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
max-width: min(440px, calc(100% - 32px));
|
||||
padding: 20px 24px;
|
||||
background: white;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
color: var(--text-color);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
.wall-offline-title { font-weight: 600; font-size: 16px; margin-bottom: 6px; }
|
||||
.wall-offline p { margin: 0 0 12px; }
|
||||
|
||||
/* Loading Overlay */
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
|
|
|
|||
Loading…
Reference in a new issue