diff --git a/.planning/STATE.md b/.planning/STATE.md index 31164dd..5848c62 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,8 +4,8 @@ milestone: v2.3 milestone_name: Global & Social Ready status: executing stopped_at: Phase 34 context gathered -last_updated: "2026-04-13T16:24:18.387Z" -last_activity: 2026-04-13 +last_updated: "2026-04-13T16:27:56.612Z" +last_activity: 2026-04-13 -- Phase 34 execution started progress: total_phases: 16 completed_phases: 6 @@ -21,14 +21,14 @@ progress: See: .planning/PROJECT.md (updated 2026-04-09) **Core value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing. -**Current focus:** Phase 34 — i18n Foundation +**Current focus:** Phase 34 — i18n-foundation ## Current Position -Phase: 999.1 -Plan: Not started +Phase: 34 (i18n-foundation) — EXECUTING +Plan: 1 of 5 Status: Executing Phase 34 -Last activity: 2026-04-13 +Last activity: 2026-04-13 -- Phase 34 execution started Progress: [░░░░░░░░░░] 0% diff --git a/.planning/phases/32-setup-sharing-system/32-UAT.md b/.planning/phases/32-setup-sharing-system/32-UAT.md new file mode 100644 index 0000000..733e005 --- /dev/null +++ b/.planning/phases/32-setup-sharing-system/32-UAT.md @@ -0,0 +1,69 @@ +--- +status: testing +phase: 32-setup-sharing-system +source: [32-01-SUMMARY.md, 32-02-SUMMARY.md, 32-03-SUMMARY.md, 32-04-SUMMARY.md] +started: 2026-04-13T18:00:00.000Z +updated: 2026-04-13T18:00:00.000Z +--- + +## Current Test + +number: 1 +name: Visibility badge on setup cards +expected: | + On the setups list page, each setup card shows a visibility indicator. Public setups show a green globe icon, link-shared show a blue link icon, and private show a gray lock icon. +awaiting: user response + +## Tests + +### 1. Visibility badge on setup cards +expected: On the setups list page, each setup card shows a visibility indicator. Public setups show a green globe icon, link-shared show a blue link icon, and private show a gray lock icon. +result: [pending] + +### 2. Share button on setup detail page +expected: On a setup detail page (as the owner), there's a "Share" button (desktop: text + icon, mobile: icon-only 44px touch target) that replaces the old public/private globe toggle. The icon reflects the current visibility state. +result: [pending] + +### 3. Share modal — visibility picker +expected: Clicking the Share button opens a modal with three visibility options: Private (gray), Link (blue), Public (green). Selecting one immediately updates the setup's visibility via API call. Current state is highlighted. +result: [pending] + +### 4. Share modal — create share link +expected: In the share modal, there's a section to create share links with an expiration dropdown (7 days, 14 days, 30 days, No expiration). Creating a link generates a URL and shows it in the active links list. +result: [pending] + +### 5. Share modal — copy and revoke links +expected: Each active share link in the modal has a copy-to-clipboard button and a revoke button. Copying puts the URL in the clipboard. Revoking removes the link from the active list. +result: [pending] + +### 6. Share modal — private deactivates links +expected: When switching visibility to "Private" while share links exist, links are deactivated (not deleted). Switching back to "Link" reactivates them. +result: [pending] + +### 7. Short URL access (/s/token) +expected: Visiting /s/{token} redirects to /setups/{id}?share={token}. The setup loads correctly showing its items and totals. +result: [pending] + +### 8. Shared setup viewer — read-only mode +expected: When viewing a setup via share token, a blue "Shared setup" banner appears at the top. All owner controls are hidden: no Add Items, no Share button, no Delete, no item removal, no classification cycling. +result: [pending] + +### 9. Invalid share token error +expected: Visiting a setup with an invalid or expired share token shows a "Link not available" error page instead of the setup content. +result: [pending] + +### 10. Discovery feed uses visibility +expected: Only setups with visibility="public" appear on the discovery feed and profile pages. Link-shared and private setups do not appear. +result: [pending] + +## Summary + +total: 10 +passed: 0 +issues: 0 +pending: 10 +skipped: 0 + +## Gaps + +[none yet] diff --git a/src/client/components/BottomTabBar.tsx b/src/client/components/BottomTabBar.tsx index 918d0d8..998f930 100644 --- a/src/client/components/BottomTabBar.tsx +++ b/src/client/components/BottomTabBar.tsx @@ -48,7 +48,11 @@ export function BottomTabBar() {
{t("externalLink.redirectMessage")}
++ {t("externalLink.redirectMessage")} +
{externalLinkUrl}
diff --git a/src/client/components/onboarding/OnboardingDone.tsx b/src/client/components/onboarding/OnboardingDone.tsx index 4331730..da34e76 100644 --- a/src/client/components/onboarding/OnboardingDone.tsx +++ b/src/client/components/onboarding/OnboardingDone.tsx @@ -24,9 +24,7 @@ export function OnboardingDone({- {t("done.subtitle")} -
+{t("done.subtitle")}
diff --git a/src/client/routes/global-items/$globalItemId.tsx b/src/client/routes/global-items/$globalItemId.tsx index 7dc9f1c..2eae2a9 100644 --- a/src/client/routes/global-items/$globalItemId.tsx +++ b/src/client/routes/global-items/$globalItemId.tsx @@ -3,14 +3,13 @@ import { useState } from "react"; import { GearImage, imageContainerBg } from "../../components/GearImage"; import { useAuth } from "../../hooks/useAuth"; import { useCurrency } from "../../hooks/useCurrency"; -import { useExchangeRates } from "../../hooks/useExchangeRates"; import { useFormatters } from "../../hooks/useFormatters"; import { useGlobalItem, useGlobalItemCommunityStats, useGlobalItemPrices, } from "../../hooks/useGlobalItems"; -import { formatPrice, type Currency } from "../../lib/formatters"; +import { type Currency, formatPrice } from "../../lib/formatters"; import { LucideIcon } from "../../lib/iconData"; import { useUIStore } from "../../stores/uiStore"; @@ -263,11 +262,8 @@ function GlobalItemDetail() { ); } -function MarketPricesSection({ - globalItemId, -}: { globalItemId: number }) { +function MarketPricesSection({ globalItemId }: { globalItemId: number }) { const { market: userMarket } = useCurrency(); - const { price } = useFormatters(); const { data: pricesData } = useGlobalItemPrices(globalItemId); const { data: communityStats } = useGlobalItemCommunityStats(globalItemId); const [showOtherMarkets, setShowOtherMarkets] = useState(false); @@ -279,9 +275,7 @@ function MarketPricesSection({ if (marketPrices.length === 0 && stats.length === 0) return null; const userMarketPrice = marketPrices.find((p) => p.market === userMarket); - const otherMarketPrices = marketPrices.filter( - (p) => p.market !== userMarket, - ); + const otherMarketPrices = marketPrices.filter((p) => p.market !== userMarket); const userMarketStats = stats.filter((s) => s.market === userMarket); const otherMarketStats = stats.filter((s) => s.market !== userMarket); @@ -293,7 +287,10 @@ function MarketPricesSection({ {userMarketPrice && (+
Community ({stat.market}):{" "}
{formatPrice(stat.medianPrice, stat.currency as Currency)} median{" "}
diff --git a/src/client/routes/settings.tsx b/src/client/routes/settings.tsx
index c6d610c..c009c72 100644
--- a/src/client/routes/settings.tsx
+++ b/src/client/routes/settings.tsx
@@ -51,10 +51,10 @@ function ApiKeySection() {
return (
- {t("apiKeys.description")}
- {t("apiKeys.description")}
- {t("importExport.description")}
- {t("importExport.description")}{t("apiKeys.title")}
-
+ {t("apiKeys.title")}
+
+ {t("importExport.title")}
-
+ {t("importExport.title")}
+
+