From d81397180910e91b0778edaebc54d26b89f2b808 Mon Sep 17 00:00:00 2001 From: everysingletear Date: Sat, 15 Aug 2026 15:45:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20ActivitiesCard=20crashes=20=E2=80=94?= =?UTF-8?q?=20t()=20in=20a=20prop=20default=20has=20no=20scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ActivitiesCard` takes its title as `({ title = t('activity.title') })`. A default parameter is evaluated in the function's own scope, where `t` does not exist: the only `t` in the file is bound inside `ActivityItem`, a separate component. `Sidepanel` renders the card without a `title`, and `activities` is `enabled: true` in `DEFAULT_SIDEPANEL_CONFIG`, so the default is always evaluated on a desktop-width screen. The hook moves into the component body and the title falls back there instead. Same rendered output; three render sites now read `displayTitle`. This is my regression: it arrived with #216, which described itself as "no behaviour change". It was not caught because a bundler cannot flag it — an unbound `t` is indistinguishable from a global — and my checks only verified that keys and imports existed, not that `t` was in scope. It is visible in the built bundle: `({title:e=t("activity.title")})` keeps the literal `t` because the minifier cannot rename a free variable, while a working call nearby minifies to `q=e("common.confirm")`. I have added an eslint `no-undef` pass to my own pipeline and run it before sending anything from now on. --- src/views/Chores/ActivitesCard.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/views/Chores/ActivitesCard.jsx b/src/views/Chores/ActivitesCard.jsx index f3088b7..b64ae3c 100644 --- a/src/views/Chores/ActivitesCard.jsx +++ b/src/views/Chores/ActivitesCard.jsx @@ -274,7 +274,9 @@ const groupActivitiesByDate = activities => { return groups } -const ActivitiesCard = ({ title = t('activity.title') }) => { +const ActivitiesCard = ({ title }) => { + const { t } = useTranslation('chores') + const displayTitle = title || t('activity.title') const [noteViewerConfig, setNoteViewerConfig] = useState({ isOpen: false }) // Use hooks to fetch data @@ -323,7 +325,7 @@ const ActivitiesCard = ({ title = t('activity.title') }) => { }} > - {title} + {displayTitle} { > - {title} + {displayTitle} { > - {title} + {displayTitle} From 64aca507aff299b7874ae5ee22d775841936cd3b Mon Sep 17 00:00:00 2001 From: everysingletear Date: Sat, 15 Aug 2026 17:02:02 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20ChoresOverview=20does=20not=20parse?= =?UTF-8?q?=20=E2=80=94=20hook=20inserted=20into=20an=20object=20literal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CHORE_STATUS` is a module-level object literal, and a `useTranslation` call ended up inside it: const CHORE_STATUS = { const { t } = useTranslation('chores') NO_DUE_DATE: 'No due date', That is a syntax error, so the file cannot be parsed at all. It does not break the build because nothing imports `ChoresOverview` — vite never compiles it — but it breaks eslint, editors, and anything else that walks the whole tree. The hook moves into the component, which is where the file's `t()` calls actually live. This one arrived with #210, the same way #216 brought the ActivitiesCard crash: my tooling wrote the hook in mechanically and nothing downstream parsed the result. Both are now covered by the `no-undef` pass I described in the other commit — it reports the parse error too. --- src/views/ChoresOverview.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/ChoresOverview.jsx b/src/views/ChoresOverview.jsx index 92cf309..1d8bef3 100644 --- a/src/views/ChoresOverview.jsx +++ b/src/views/ChoresOverview.jsx @@ -33,7 +33,6 @@ import DateModal from './Modals/Inputs/DateModal' // enum for chore status: const CHORE_STATUS = { - const { t } = useTranslation('chores') NO_DUE_DATE: 'No due date', DUE_SOON: 'Soon', DUE_NOW: 'Due', @@ -41,6 +40,7 @@ const CHORE_STATUS = { } const ChoresOverview = () => { + const { t } = useTranslation('chores') const [chores, setChores] = useState([]) const [filteredChores, setFilteredChores] = useState([]) const [performers, setPerformers] = useState([])