feature(area): activity feed extended#887
Conversation
✅ Deploy Preview for btcmap ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 45 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughExtracted area activity feed into a new AreaFeed component that handles fetching, pagination, race-condition guards, and UI states; AreaActivity now delegates to AreaFeed and AreaPage no longer builds ActivityEvent objects, only collects tagger metadata. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant AreaFeed
participant BTCMapAPI as "BTCMap API"
participant UI
User->>AreaFeed: provide alias, name, dataInitialized
rect rgba(100,150,255,0.5)
Note over AreaFeed: reset state (days=30, clear items, inc fetchGeneration)
AreaFeed->>BTCMapAPI: GET /activity?alias&days=30
BTCMapAPI-->>AreaFeed: feedItems[]
AreaFeed->>AreaFeed: store items, set loading=false
end
AreaFeed->>UI: render feed entries / skeleton / error / empty
User->>AreaFeed: click "Load more"
rect rgba(100,150,255,0.5)
Note over AreaFeed: increment days, inc fetchGeneration, fetch append
AreaFeed->>BTCMapAPI: GET /activity?alias&days=60
BTCMapAPI-->>AreaFeed: additionalItems[]
AreaFeed->>AreaFeed: append items, restore scrollTop
AreaFeed->>UI: re-render feed with preserved scroll
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Replace the area activity section with a new AreaFeed component that
fetches from /v4/activity?area={alias}, showing edits, comments, and
boosts in a single chronological timeline. Taggers and atom feed
sections remain unchanged.
In dev mode, requests proxy through /local-api to localhost:8000 for
testing against a local API server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove dead code: eventElements, ActivityEvent import, formatElementID - Remove unused TopButton import from AreaFeed - Fix key collisions by appending index to each key - Add error state with retry button instead of silent error swallowing - Add generation counter to prevent stale responses on area navigation - Preserve scroll position on load-more - Remove unused fields from ActivityItem type Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/components/area/AreaFeed.svelte (3)
54-65: Scroll restoration may not work reliably with async timing.The
requestAnimationFrameschedules scroll restoration after the next paint, but Svelte's DOM updates afterfeedItemsassignment may not complete by then. Consider usingtick()from Svelte to ensure the DOM has updated before restoring scroll position.♻️ Use Svelte's tick() for reliable DOM update timing
+import { tick } from "svelte"; + const loadMore = () => { const scrollTop = feedDiv?.scrollTop; days = days + 30; - fetchFeed(true).then(() => { - // Restore scroll position after re-render + fetchFeed(true).then(async () => { + await tick(); if (feedDiv && scrollTop) { - requestAnimationFrame(() => { - feedDiv.scrollTop = scrollTop; - }); + feedDiv.scrollTop = scrollTop; } }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 54 - 65, The scroll restoration in loadMore currently uses requestAnimationFrame which can race with Svelte's DOM updates; change loadMore to await fetchFeed(true), then call Svelte's tick() (import { tick } from 'svelte') to ensure DOM updates for feedItems have flushed before restoring feedDiv.scrollTop; after awaiting tick(), set feedDiv.scrollTop back (guarding feedDiv and saved scrollTop != null) instead of using requestAnimationFrame.
67-72: Reactive block triggers fetch on everyaliasordataInitializedchange.The reactive statement will re-run whenever either dependency changes. If
dataInitializedtoggles multiple times oraliasis reassigned to the same value, this could trigger redundant fetches. The generation guard mitigates stale responses, but consider adding a check to avoid unnecessary network calls.♻️ Optional: Track previous alias to avoid redundant fetches
+let prevAlias: string | null = null; + $: if (dataInitialized && alias) { + if (alias === prevAlias) return; + prevAlias = alias; days = 30; feedItems = []; error = false; fetchFeed(false); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 67 - 72, The reactive block currently re-runs and calls fetchFeed whenever dataInitialized or alias changes; add a small guard to avoid redundant network calls by tracking the previous alias and only invoking fetchFeed when dataInitialized becomes true and alias is non-empty and different from the last-used alias (store lastAlias in the component state), or when you explicitly want to reset (e.g., when days is changed). Update the block that references dataInitialized and alias (and sets days, feedItems, error) to compare alias against lastAlias and only call fetchFeed(false) when alias !== lastAlias (then assign lastAlias = alias).
35-52: Theappendparameter doesn't actually append items.The function signature accepts
append: boolean, butfeedItems = res.dataalways replaces the entire array. If appending was intended (for "load more" behavior), the logic should concatenate. However, since the API returns all items within thedayswindow, replacing is likely correct—consider removing the misleading parameter name.♻️ Suggested clarification
-const fetchFeed = async (append: boolean) => { +const fetchFeed = async (isRetry: boolean = false) => { loading = true; error = false; const gen = ++fetchGeneration; try { const base = dev ? "/local-api" : "https://api.btcmap.org"; const url = `${base}/v4/activity?area=${encodeURIComponent(alias)}&days=${days}`; const res = await api.get<ActivityItem[]>(url); - // Discard stale response if user navigated to a different area if (gen !== fetchGeneration) return; feedItems = res.data; } catch { if (gen !== fetchGeneration) return; - if (!append) feedItems = []; + if (!isRetry) feedItems = []; error = true; } loading = false; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 35 - 52, The fetchFeed function declares an unused append boolean and branches on it (e.g., "append" parameter, "if (!append) feedItems = [];") but the code always replaces feedItems with res.data; either implement true append behavior or remove the misleading parameter. Fix by removing the append parameter from fetchFeed and all callers, delete the append-specific conditional logic inside fetchFeed (the "if (!append) feedItems = []" branch), and keep the single replacement assignment feedItems = res.data; alternatively, if you prefer load-more semantics implement concatenation (feedItems = [...feedItems, ...res.data]) and keep append semantics consistent in callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 222-231: When rendering the error branch (the template using the
error boolean and the fetchFeed(false) retry handler), replace the misleading
no-activity text with an explicit error message key (use
$_('areaActivity.errorLoading')) and make the Retry button label use i18n
($_('areaActivity.retry')) instead of a hardcoded "Retry"; also add the new
translation keys areaActivity.errorLoading and areaActivity.retry to your i18n
files. Ensure the on:click still calls fetchFeed(false) and keep the existing
classes/structure.
---
Nitpick comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 54-65: The scroll restoration in loadMore currently uses
requestAnimationFrame which can race with Svelte's DOM updates; change loadMore
to await fetchFeed(true), then call Svelte's tick() (import { tick } from
'svelte') to ensure DOM updates for feedItems have flushed before restoring
feedDiv.scrollTop; after awaiting tick(), set feedDiv.scrollTop back (guarding
feedDiv and saved scrollTop != null) instead of using requestAnimationFrame.
- Around line 67-72: The reactive block currently re-runs and calls fetchFeed
whenever dataInitialized or alias changes; add a small guard to avoid redundant
network calls by tracking the previous alias and only invoking fetchFeed when
dataInitialized becomes true and alias is non-empty and different from the
last-used alias (store lastAlias in the component state), or when you explicitly
want to reset (e.g., when days is changed). Update the block that references
dataInitialized and alias (and sets days, feedItems, error) to compare alias
against lastAlias and only call fetchFeed(false) when alias !== lastAlias (then
assign lastAlias = alias).
- Around line 35-52: The fetchFeed function declares an unused append boolean
and branches on it (e.g., "append" parameter, "if (!append) feedItems = [];")
but the code always replaces feedItems with res.data; either implement true
append behavior or remove the misleading parameter. Fix by removing the append
parameter from fetchFeed and all callers, delete the append-specific conditional
logic inside fetchFeed (the "if (!append) feedItems = []" branch), and keep the
single replacement assignment feedItems = res.data; alternatively, if you prefer
load-more semantics implement concatenation (feedItems = [...feedItems,
...res.data]) and keep append semantics consistent in callers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b2f9a5fc-d89f-4259-8db1-b9acd08ece6f
📒 Files selected for processing (4)
src/components/area/AreaActivity.sveltesrc/components/area/AreaFeed.sveltesrc/components/area/AreaPage.sveltevite.config.ts
Both osm_user_id and osm_user_name must be present before rendering the tagger link, since both fields are optional in the API response. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
If the fetch fails, restore the previous days value so the next retry attempts the same range instead of skipping ahead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When navigating between areas, the scroll chevron indicator stayed hidden. Reset it so the new feed shows the chevron again. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add areaActivity.loadError and areaActivity.retry i18n keys. Error state now shows distinct message instead of reusing noActivity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split mixed import statement per CLAUDE.md guidelines — type-only imports use `import type`, runtime values use separate `import`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5d72299 to
21043c3
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/components/area/AreaFeed.svelte (2)
145-151: Use i18n for activity action labels.The strings "created", "deleted", "updated" are hardcoded in English. For consistency with the rest of the application, these should use translation keys.
♻️ Suggested refactor
was <strong - >{item.type === 'place_added' - ? 'created' - : item.type === 'place_deleted' - ? 'deleted' - : 'updated'}</strong + >{item.type === 'place_added' + ? $_('areaActivity.created') + : item.type === 'place_deleted' + ? $_('areaActivity.deleted') + : $_('areaActivity.updated')}</strong >Add the corresponding keys to your i18n files:
"areaActivity": { "created": "created", "deleted": "deleted", "updated": "updated" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 145 - 151, Replace the hardcoded English action labels in AreaFeed.svelte (the ternary using item.type) with i18n lookups so the UI uses translation keys (e.g., areaActivity.created / areaActivity.deleted / areaActivity.updated) instead of the literal strings; update your i18n resource files to include those keys and ensure the component imports/uses the translation function (or $t store) the app uses so the ternary returns translated labels for item.type === 'place_added' | 'place_deleted' | otherwise.
193-193: Use i18n with pluralization for boost duration.The text "was boosted for {duration} days" is hardcoded. Consider using an i18n key with ICU pluralization to handle "1 day" vs "N days" correctly across languages.
♻️ Suggested refactor
-was <strong>boosted</strong> for {item.duration_days} days +{$_('areaActivity.boosted', { values: { days: item.duration_days } })}With i18n key:
"boosted": "was <strong>boosted</strong> for {days, plural, one {# day} other {# days}}"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` at line 193, The hardcoded fragment "was <strong>boosted</strong> for {item.duration_days} days" should be replaced with an i18n key using ICU pluralization so "1 day" vs "N days" is correct and the <strong> markup is preserved; add a translation key like "boosted": "was <strong>boosted</strong> for {days, plural, one {# day} other {# days}}" and update the AreaFeed.svelte usage to call your i18n translate function (e.g., t or $t) passing days: item.duration_days and render the translated string as HTML-safe content so the <strong> stays bold. Ensure you reference the string in AreaFeed.svelte where item.duration_days is used and remove the hardcoded sentence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 145-151: Replace the hardcoded English action labels in
AreaFeed.svelte (the ternary using item.type) with i18n lookups so the UI uses
translation keys (e.g., areaActivity.created / areaActivity.deleted /
areaActivity.updated) instead of the literal strings; update your i18n resource
files to include those keys and ensure the component imports/uses the
translation function (or $t store) the app uses so the ternary returns
translated labels for item.type === 'place_added' | 'place_deleted' | otherwise.
- Line 193: The hardcoded fragment "was <strong>boosted</strong> for
{item.duration_days} days" should be replaced with an i18n key using ICU
pluralization so "1 day" vs "N days" is correct and the <strong> markup is
preserved; add a translation key like "boosted": "was <strong>boosted</strong>
for {days, plural, one {# day} other {# days}}" and update the AreaFeed.svelte
usage to call your i18n translate function (e.g., t or $t) passing days:
item.duration_days and render the translated string as HTML-safe content so the
<strong> stays bold. Ensure you reference the string in AreaFeed.svelte where
item.duration_days is used and remove the hardcoded sentence.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3e4317c7-69ad-49c9-8c9d-5c8cbf920c81
📒 Files selected for processing (5)
src/components/area/AreaActivity.sveltesrc/components/area/AreaFeed.sveltesrc/components/area/AreaPage.sveltesrc/lib/i18n/locales/en.jsonvite.config.ts
✅ Files skipped from review due to trivial changes (2)
- src/lib/i18n/locales/en.json
- vite.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/area/AreaActivity.svelte
Replace magic number 30 with named constant for clarity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the /local-api proxy from vite.config.ts and the dev/prod URL toggle from AreaFeed. A proper local dev solution can be designed later across the whole app. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/components/area/AreaFeed.svelte (3)
145-159: Hardcoded English strings should use i18n for consistency.The component uses
$_()for translations elsewhere but has hardcoded strings here: "created", "deleted", "updated", and "by". For i18n consistency, consider adding translation keys.♻️ Proposed i18n approach
was <strong >{item.type === 'place_added' - ? 'created' + ? $_('areaActivity.created') : item.type === 'place_deleted' - ? 'deleted' - : 'updated'}</strong + ? $_('areaActivity.deleted') + : $_('areaActivity.updated')}</strong > {`#if` item.osm_user_id && item.osm_user_name} - by <a + {$_('areaActivity.by')} <a href={resolve(`/tagger/${item.osm_user_id}`)} class="break-all text-link transition-colors hover:text-hover" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 145 - 159, The template in AreaFeed.svelte is using hardcoded English strings for the place status and the "by" prefix (the ternary block checking item.type and the literal "by"); replace those literals with i18n lookups (use the existing $_() helper used elsewhere) e.g. map item.type to translation keys like $_('place.created'), $_('place.deleted'), $_('place.updated') and replace "by" with $_('by') (or project-appropriate keys), update your i18n resource files with those keys, and ensure the $_ helper is available in the component scope before rendering.
193-193: Hardcoded boost message should use i18n with interpolation.This string should also use a translation key with a placeholder for the duration.
♻️ Proposed fix
-was <strong>boosted</strong> for {item.duration_days} days +{$_('areaActivity.boosted', { values: { days: item.duration_days } })}Translation key example:
"boosted": "was <strong>boosted</strong> for {days} days"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` at line 193, Replace the hardcoded HTML string in AreaFeed.svelte ("was <strong>boosted</strong> for {item.duration_days} days") with an i18n translation key that includes an interpolation placeholder for days (e.g., add a translation entry "boosted": "was <strong>boosted</strong> for {days} days") and render it using the project's translation helper, passing item.duration_days as the days parameter so the UI uses localized text with the correct duration.
104-130: Consider simplifying dot rendering with a color map.The five conditional blocks are nearly identical, differing only in the background color. A mapping would reduce duplication.
♻️ Optional simplification
Add a helper in the script section:
const dotColor: Record<string, string> = { place_commented: 'bg-amber-500', place_boosted: 'bg-orange-500', place_added: 'bg-created', place_deleted: 'bg-deleted' };Then in the template:
{`@const` color = dotColor[item.type] ?? 'bg-link'} <span class="relative mx-auto mb-2 flex h-3 w-3 lg:mx-0 lg:mb-0"> <span class="{i === 0 ? 'animate-ping' : ''} absolute inline-flex h-full w-full rounded-full {color} opacity-75" /> <span class="relative inline-flex h-3 w-3 rounded-full {color}" /> </span>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 104 - 130, The repeated conditional dot-rendering based on item.type should be replaced by a color map to remove duplication: add a helper (e.g., const dotColor: Record<string,string>) mapping 'place_commented','place_boosted','place_added','place_deleted' to their respective Tailwind classes and fall back to 'bg-link', then in the template compute const color = dotColor[item.type] ?? 'bg-link' and render a single wrapper <span> containing two spans using {i === 0 ? 'animate-ping' : ''} for the absolute pulsing layer and the solid dot layer both using the computed {color} classes instead of the multiple {:if} branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 145-159: The template in AreaFeed.svelte is using hardcoded
English strings for the place status and the "by" prefix (the ternary block
checking item.type and the literal "by"); replace those literals with i18n
lookups (use the existing $_() helper used elsewhere) e.g. map item.type to
translation keys like $_('place.created'), $_('place.deleted'),
$_('place.updated') and replace "by" with $_('by') (or project-appropriate
keys), update your i18n resource files with those keys, and ensure the $_ helper
is available in the component scope before rendering.
- Line 193: Replace the hardcoded HTML string in AreaFeed.svelte ("was
<strong>boosted</strong> for {item.duration_days} days") with an i18n
translation key that includes an interpolation placeholder for days (e.g., add a
translation entry "boosted": "was <strong>boosted</strong> for {days} days") and
render it using the project's translation helper, passing item.duration_days as
the days parameter so the UI uses localized text with the correct duration.
- Around line 104-130: The repeated conditional dot-rendering based on item.type
should be replaced by a color map to remove duplication: add a helper (e.g.,
const dotColor: Record<string,string>) mapping
'place_commented','place_boosted','place_added','place_deleted' to their
respective Tailwind classes and fall back to 'bg-link', then in the template
compute const color = dotColor[item.type] ?? 'bg-link' and render a single
wrapper <span> containing two spans using {i === 0 ? 'animate-ping' : ''} for
the absolute pulsing layer and the solid dot layer both using the computed
{color} classes instead of the multiple {:if} branches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cee2a433-a919-4690-8527-f56bf867d3d0
📒 Files selected for processing (1)
src/components/area/AreaFeed.svelte
Add areaActivity.was, created, updated, deleted, by, boosted, and commented i18n keys. The boosted string uses interpolation for the duration days value and @html for the <strong> tag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 5 conditional branches with a DOT_COLORS lookup map and a dotColor() helper. Adding new activity types now only requires a map entry instead of duplicating the dot markup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/components/area/AreaFeed.svelte (1)
46-62: Consider clarifying theappendparameter semantics.The
appendparameter only affects error handling (line 58) and doesn't actually append on success—line 55 always replacesfeedItems. This is likely intentional since the API returns cumulative data for thedayswindow, but the parameter name is misleading.✏️ Suggested rename for clarity
-const fetchFeed = async (append: boolean) => { +const fetchFeed = async (preserveOnError: boolean) => { loading = true; error = false; const gen = ++fetchGeneration; try { const url = `https://api.btcmap.org/v4/activity?area=${encodeURIComponent(alias)}&days=${days}`; const res = await api.get<ActivityItem[]>(url); // Discard stale response if user navigated to a different area if (gen !== fetchGeneration) return; feedItems = res.data; } catch { if (gen !== fetchGeneration) return; - if (!append) feedItems = []; + if (!preserveOnError) feedItems = []; error = true; } loading = false; };Then update callsites:
fetchFeed(false)→fetchFeed(false)(unchanged),fetchFeed(true)→fetchFeed(true)(unchanged, but now the meaning is clearer).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/area/AreaFeed.svelte` around lines 46 - 62, The parameter append on fetchFeed only controls whether feedItems is cleared on error and doesn't append on success, so rename the parameter to something that reflects that behavior (e.g., preserveOnError or suppressClearOnError) in the fetchFeed function signature and its usages; update any inline comment/docstring for fetchFeed to describe "preserve existing feed on error" semantics, replace all callsites passing true/false to use the new parameter name, and ensure references to feedItems and the error branch logic (the if (!append) feedItems = [] block) are updated to use the new identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 108-201: The loadMore failure currently sets error=true but
because the template first checks feedItems.length the error UI never appears;
update the loadMore handler to track a dedicated loadMoreError state (e.g.,
loadMoreError or loadMoreFailed) and set it when the fetch rejects, then update
the template around the Load more button (the button with on:click={loadMore})
to show inline feedback — disable the button when loading or loadMoreError, add
error styling/text or a small toast/inline message adjacent to that button, and
ensure feed rendering (feedItems) remains unchanged while the user clearly sees
the loadMore failure.
---
Nitpick comments:
In `@src/components/area/AreaFeed.svelte`:
- Around line 46-62: The parameter append on fetchFeed only controls whether
feedItems is cleared on error and doesn't append on success, so rename the
parameter to something that reflects that behavior (e.g., preserveOnError or
suppressClearOnError) in the fetchFeed function signature and its usages; update
any inline comment/docstring for fetchFeed to describe "preserve existing feed
on error" semantics, replace all callsites passing true/false to use the new
parameter name, and ensure references to feedItems and the error branch logic
(the if (!append) feedItems = [] block) are updated to use the new identifier.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fea82ab3-7266-4103-86d8-18211fe14364
📒 Files selected for processing (2)
src/components/area/AreaFeed.sveltesrc/lib/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/i18n/locales/en.json
When load-more fails with existing items, the error state was unreachable because the feedItems.length branch always wins. Now an inline error with retry button renders above the load-more button when a pagination fetch fails. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Translations should not contain HTML — keeps translation files plain text and avoids @html in the template. The boosted phrase is now composed from areaActivity.was, areaActivity.boosted (plain), and areaActivity.forDays with days interpolation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The append param was misleading — fetchFeed always replaces feedItems with fresh API data, never concatenates. The flag only controlled whether to clear items on error. Replaced with an internal hadItems check based on current state, simpler and clearer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Based on this BE PR: teambtcmap/btcmap-api#79
Only first iteration to get things started
Summary by CodeRabbit
New Features
Reliability
Bug Fixes