fix: resolve lint errors from phase 32/33/34 execution
Auto-fixed formatting issues and removed unused imports introduced by background execution agents across currency, i18n, and sharing code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,7 +48,11 @@ export function BottomTabBar() {
|
||||
<div className="flex justify-around">
|
||||
{/* Home tab — always a Link */}
|
||||
<Link to="/">
|
||||
<TabItemWrapper icon="house" label={t("nav.home")} isActive={isHome} />
|
||||
<TabItemWrapper
|
||||
icon="house"
|
||||
label={t("nav.home")}
|
||||
isActive={isHome}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{/* Collection tab — Link if authenticated, button if anonymous */}
|
||||
@@ -73,17 +77,29 @@ export function BottomTabBar() {
|
||||
{/* Setups tab — Link if authenticated, button if anonymous */}
|
||||
{isAuthenticated ? (
|
||||
<Link to="/setups">
|
||||
<TabItemWrapper icon="layers" label={t("nav.setups")} isActive={isSetups} />
|
||||
<TabItemWrapper
|
||||
icon="layers"
|
||||
label={t("nav.setups")}
|
||||
isActive={isSetups}
|
||||
/>
|
||||
</Link>
|
||||
) : (
|
||||
<button type="button" onClick={openAuthPrompt}>
|
||||
<TabItemWrapper icon="layers" label={t("nav.setups")} isActive={isSetups} />
|
||||
<TabItemWrapper
|
||||
icon="layers"
|
||||
label={t("nav.setups")}
|
||||
isActive={isSetups}
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Search tab — always a button, opens CatalogSearchOverlay */}
|
||||
<button type="button" onClick={() => openCatalogSearch("collection")}>
|
||||
<TabItemWrapper icon="search" label={t("nav.search")} isActive={false} />
|
||||
<TabItemWrapper
|
||||
icon="search"
|
||||
label={t("nav.search")}
|
||||
isActive={false}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -39,7 +39,9 @@ export function ExternalLinkDialog() {
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
||||
{t("externalLink.title")}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 mb-1">{t("externalLink.redirectMessage")}</p>
|
||||
<p className="text-sm text-gray-600 mb-1">
|
||||
{t("externalLink.redirectMessage")}
|
||||
</p>
|
||||
<p className="text-sm text-gray-600 break-all mb-6">
|
||||
{externalLinkUrl}
|
||||
</p>
|
||||
|
||||
@@ -24,9 +24,7 @@ export function OnboardingDone({
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">
|
||||
{t("done.title")}
|
||||
</h1>
|
||||
<p className="text-base text-gray-500 mb-8">
|
||||
{t("done.subtitle")}
|
||||
</p>
|
||||
<p className="text-base text-gray-500 mb-8">{t("done.subtitle")}</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onFinish}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { HOBBIES } from "@/shared/hobbyConfig";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HOBBIES } from "@/shared/hobbyConfig";
|
||||
import { HobbyCard } from "./HobbyCard";
|
||||
|
||||
interface OnboardingHobbyPickerProps {
|
||||
@@ -20,9 +20,7 @@ export function OnboardingHobbyPicker({
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">
|
||||
{t("hobby.title")}
|
||||
</h1>
|
||||
<p className="text-base text-gray-500 mb-8">
|
||||
{t("hobby.subtitle")}
|
||||
</p>
|
||||
<p className="text-base text-gray-500 mb-8">{t("hobby.subtitle")}</p>
|
||||
<div className="flex flex-wrap justify-center gap-4 mb-8">
|
||||
{HOBBIES.map((hobby) => (
|
||||
<HobbyCard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getTagsForHobbies } from "@/shared/hobbyConfig";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTagsForHobbies } from "@/shared/hobbyConfig";
|
||||
import { usePopularItems } from "../../hooks/useOnboarding";
|
||||
import { SelectableItemCard } from "./SelectableItemCard";
|
||||
|
||||
@@ -54,9 +54,7 @@ export function OnboardingItemBrowser({
|
||||
? t("items.title", { hobby: selectedHobbies[0] })
|
||||
: t("items.titleMultiple")}
|
||||
</h1>
|
||||
<p className="text-base text-gray-500 mb-8">
|
||||
{t("items.subtitle")}
|
||||
</p>
|
||||
<p className="text-base text-gray-500 mb-8">{t("items.subtitle")}</p>
|
||||
|
||||
{isLoading && (
|
||||
<div className="flex justify-center py-12">
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import type { Currency } from "../lib/formatters";
|
||||
import { useSetting } from "./useSettings";
|
||||
|
||||
const VALID_CURRENCIES: Currency[] = [
|
||||
"USD",
|
||||
"EUR",
|
||||
"GBP",
|
||||
"JPY",
|
||||
"CAD",
|
||||
"AUD",
|
||||
];
|
||||
const VALID_CURRENCIES: Currency[] = ["USD", "EUR", "GBP", "JPY", "CAD", "AUD"];
|
||||
|
||||
const CURRENCY_MARKET_MAP: Record<string, string> = {
|
||||
EUR: "EU",
|
||||
|
||||
@@ -70,7 +70,11 @@ export function formatDualPrice(options: DualPriceOptions): {
|
||||
converted: string;
|
||||
} {
|
||||
const locale = options.locale ?? "en";
|
||||
const source = formatPrice(options.sourceCents, options.sourceCurrency, locale);
|
||||
const source = formatPrice(
|
||||
options.sourceCents,
|
||||
options.sourceCurrency,
|
||||
locale,
|
||||
);
|
||||
const converted = `~${formatPrice(options.convertedCents, options.targetCurrency, locale)}`;
|
||||
return { source, converted };
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import i18n from "i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
|
||||
import enCollection from "../locales/en/collection.json";
|
||||
import enCommon from "../locales/en/common.json";
|
||||
import enOnboarding from "../locales/en/onboarding.json";
|
||||
import enSettings from "../locales/en/settings.json";
|
||||
import enSetups from "../locales/en/setups.json";
|
||||
import enThreads from "../locales/en/threads.json";
|
||||
|
||||
import deCollection from "../locales/de/collection.json";
|
||||
import deCommon from "../locales/de/common.json";
|
||||
import deOnboarding from "../locales/de/onboarding.json";
|
||||
import deSettings from "../locales/de/settings.json";
|
||||
import deSetups from "../locales/de/setups.json";
|
||||
import deThreads from "../locales/de/threads.json";
|
||||
import enCollection from "../locales/en/collection.json";
|
||||
import enCommon from "../locales/en/common.json";
|
||||
import enOnboarding from "../locales/en/onboarding.json";
|
||||
import enSettings from "../locales/en/settings.json";
|
||||
import enSetups from "../locales/en/setups.json";
|
||||
import enThreads from "../locales/en/threads.json";
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
|
||||
@@ -59,9 +59,7 @@ function RootErrorBoundary({ error, reset }: ErrorComponentProps) {
|
||||
{t("errors.somethingWentWrong")}
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500 mb-6">
|
||||
{error instanceof Error
|
||||
? error.message
|
||||
: t("errors.unexpectedError")}
|
||||
{error instanceof Error ? error.message : t("errors.unexpectedError")}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@@ -259,7 +257,9 @@ function CandidateDeleteDialog({
|
||||
disabled={deleteCandidate.isPending}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 disabled:opacity-50 rounded-lg transition-colors"
|
||||
>
|
||||
{deleteCandidate.isPending ? t("actions.deleting") : t("actions.delete")}
|
||||
{deleteCandidate.isPending
|
||||
? t("actions.deleting")
|
||||
: t("actions.delete")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -321,7 +321,9 @@ function ResolveDialog({
|
||||
disabled={resolveThread.isPending}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-amber-600 hover:bg-amber-700 disabled:opacity-50 rounded-lg transition-colors"
|
||||
>
|
||||
{resolveThread.isPending ? t("actions.saving") : t("confirm.pickWinner")}
|
||||
{resolveThread.isPending
|
||||
? t("actions.saving")
|
||||
: t("confirm.pickWinner")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 && (
|
||||
<div className="mb-2">
|
||||
<span className="text-lg font-semibold text-gray-900">
|
||||
{formatPrice(userMarketPrice.priceCents, userMarketPrice.currency as Currency)}
|
||||
{formatPrice(
|
||||
userMarketPrice.priceCents,
|
||||
userMarketPrice.currency as Currency,
|
||||
)}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500 ml-2">
|
||||
MSRP ({userMarketPrice.market})
|
||||
@@ -303,7 +300,10 @@ function MarketPricesSection({
|
||||
|
||||
{/* Community stats for user's market */}
|
||||
{userMarketStats.map((stat) => (
|
||||
<p key={`${stat.market}-${stat.currency}`} className="text-sm text-gray-700 mb-1">
|
||||
<p
|
||||
key={`${stat.market}-${stat.currency}`}
|
||||
className="text-sm text-gray-700 mb-1"
|
||||
>
|
||||
Community ({stat.market}):{" "}
|
||||
{formatPrice(stat.medianPrice, stat.currency as Currency)} median{" "}
|
||||
<span className="text-xs text-gray-400">
|
||||
|
||||
@@ -51,10 +51,10 @@ function ApiKeySection() {
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("apiKeys.title")}</h3>
|
||||
<p className="text-xs text-gray-500">
|
||||
{t("apiKeys.description")}
|
||||
</p>
|
||||
<h3 className="text-sm font-medium text-gray-900">
|
||||
{t("apiKeys.title")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">{t("apiKeys.description")}</p>
|
||||
|
||||
{newKey && (
|
||||
<div className="bg-amber-50 border border-amber-200 rounded-lg p-3">
|
||||
@@ -151,10 +151,10 @@ function ImportExportSection() {
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("importExport.title")}</h3>
|
||||
<p className="text-xs text-gray-500">
|
||||
{t("importExport.description")}
|
||||
</p>
|
||||
<h3 className="text-sm font-medium text-gray-900">
|
||||
{t("importExport.title")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">{t("importExport.description")}</p>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
@@ -166,7 +166,9 @@ function ImportExportSection() {
|
||||
</button>
|
||||
|
||||
<label className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-200 hover:bg-gray-50 rounded-lg transition-colors cursor-pointer">
|
||||
{importItems.isPending ? t("importExport.importing") : t("importExport.import")}
|
||||
{importItems.isPending
|
||||
? t("importExport.importing")
|
||||
: t("importExport.import")}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
@@ -192,7 +194,11 @@ function ImportExportSection() {
|
||||
</p>
|
||||
)}
|
||||
{importResult.createdCategories.length > 0 && (
|
||||
<p>{t("importExport.newCategories", { categories: importResult.createdCategories.join(", ") })}</p>
|
||||
<p>
|
||||
{t("importExport.newCategories", {
|
||||
categories: importResult.createdCategories.join(", "),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
{importResult.errors.map((err, i) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: static error list
|
||||
@@ -289,7 +295,9 @@ function SettingsPage() {
|
||||
<div className="bg-white rounded-xl border border-gray-100 p-5 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("language.title")}</h3>
|
||||
<h3 className="text-sm font-medium text-gray-900">
|
||||
{t("language.title")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
{t("language.description")}
|
||||
</p>
|
||||
@@ -319,7 +327,9 @@ function SettingsPage() {
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("weightUnit.title")}</h3>
|
||||
<h3 className="text-sm font-medium text-gray-900">
|
||||
{t("weightUnit.title")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
{t("weightUnit.description")}
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user