i18n
This commit is contained in:
@@ -3,6 +3,7 @@ import { useAuth } from "@/contexts/auth-context";
|
||||
import { Flex, Title, ActionIcon, Stack, Button, Box } from "@mantine/core";
|
||||
import { PencilIcon, FootballHelmetIcon } from "@phosphor-icons/react";
|
||||
import { useMemo } from "react";
|
||||
import { useLingui } from "@lingui/react/macro";
|
||||
import NameUpdateForm from "./name-form";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
@@ -14,6 +15,7 @@ interface HeaderProps {
|
||||
}
|
||||
|
||||
const Header = ({ player }: HeaderProps) => {
|
||||
const { t } = useLingui();
|
||||
const nameSheet = useSheet();
|
||||
const h2hSheet = useSheet();
|
||||
const { user: authUser } = useAuth();
|
||||
@@ -80,12 +82,12 @@ const Header = ({ player }: HeaderProps) => {
|
||||
</Flex>
|
||||
</Stack>
|
||||
|
||||
<Sheet title='Update Name' {...nameSheet.props}>
|
||||
<Sheet title={t`Update Name`} {...nameSheet.props}>
|
||||
<NameUpdateForm player={player} toggle={nameSheet.toggle} />
|
||||
</Sheet>
|
||||
|
||||
{!owner && authUser && (
|
||||
<Sheet title="Head to Head" {...h2hSheet.props}>
|
||||
<Sheet title={t`Head to Head`} {...h2hSheet.props}>
|
||||
<PlayerHeadToHeadSheet
|
||||
player1Id={authUser.id}
|
||||
player1Name={authUserName}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, Stack, Text, Divider, Group, Button, Anchor } from "@mantine/core";
|
||||
import { Suspense, useState, useDeferredValue } from "react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import Header from "./header";
|
||||
import SwipeableTabs from "@/components/swipeable-tabs";
|
||||
@@ -22,11 +23,11 @@ const StatsWithFilter = ({ id }: { id: string }) => {
|
||||
return (
|
||||
<Stack>
|
||||
<Group gap="xs" px="md" justify="space-between" align="center">
|
||||
<Text size="md" fw={700}>Statistics</Text>
|
||||
<Text size="md" fw={700}><Trans>Statistics</Trans></Text>
|
||||
<Group gap="xs">
|
||||
<Button variant={viewType === 'all' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('all')}>All</Button>
|
||||
<Button variant={viewType === 'mainline' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('mainline')}>Mainline</Button>
|
||||
<Button variant={viewType === 'regional' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('regional')}>Regional</Button>
|
||||
<Button variant={viewType === 'all' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('all')}><Trans>All</Trans></Button>
|
||||
<Button variant={viewType === 'mainline' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('mainline')}><Trans>Mainline</Trans></Button>
|
||||
<Button variant={viewType === 'regional' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('regional')}><Trans>Regional</Trans></Button>
|
||||
</Group>
|
||||
</Group>
|
||||
<Box style={{ opacity: isStale ? 0.6 : 1, transition: 'opacity 150ms' }}>
|
||||
@@ -44,18 +45,20 @@ const StatsContent = ({ id, viewType }: { id: string; viewType: 'all' | 'mainlin
|
||||
};
|
||||
|
||||
const Profile = ({ id }: ProfileProps) => {
|
||||
const { t } = useLingui();
|
||||
const { data: player } = usePlayer(id);
|
||||
const { data: matches } = usePlayerMatches(id);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: "Overview",
|
||||
label: t`Overview`,
|
||||
value: "overview",
|
||||
content: <>
|
||||
<Stack px="md">
|
||||
<Group justify="space-between" align="center">
|
||||
<Text size="md" fw={700}>Badges</Text>
|
||||
<Text size="md" fw={700}><Trans>Badges</Trans></Text>
|
||||
<Anchor component={Link} to="/badges" size="sm" fw={500}>
|
||||
View all badges
|
||||
<Trans>View all badges</Trans>
|
||||
</Anchor>
|
||||
</Group>
|
||||
<Suspense fallback={<BadgeShowcaseSkeleton />}>
|
||||
@@ -67,11 +70,13 @@ const Profile = ({ id }: ProfileProps) => {
|
||||
</>,
|
||||
},
|
||||
{
|
||||
label: "Matches",
|
||||
label: t`Matches`,
|
||||
value: "matches",
|
||||
content: <MatchList matches={matches || []} />,
|
||||
},
|
||||
{
|
||||
label: "Teams",
|
||||
label: t`Teams`,
|
||||
value: "teams",
|
||||
content: <TeamList teams={player.teams || []} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { updatePlayer } from "@/features/players/server";
|
||||
import { Stack, TextInput } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { Player } from "../../types";
|
||||
import Button from "@/components/button";
|
||||
import { useOptimisticMutation } from "@/lib/tanstack-query/hooks";
|
||||
@@ -12,6 +13,8 @@ interface NameUpdateFormProps {
|
||||
}
|
||||
|
||||
const NameUpdateForm = ({ player, toggle }: NameUpdateFormProps) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
first_name: player.first_name,
|
||||
@@ -19,14 +22,14 @@ const NameUpdateForm = ({ player, toggle }: NameUpdateFormProps) => {
|
||||
},
|
||||
validate: {
|
||||
first_name: (value: string | undefined) => {
|
||||
if (!value || value.length === 0) return "First name is required";
|
||||
if (!value || value.length === 0) return t`First name is required`;
|
||||
if (!/^[a-zA-Z\s]{2,20}$/.test(value))
|
||||
return "First name must be 2-20 characters long and contain only letters";
|
||||
return t`First name must be 2-20 characters long and contain only letters`;
|
||||
},
|
||||
last_name: (value: string | undefined) => {
|
||||
if (!value || value.length === 0) return "Last name is required";
|
||||
if (!value || value.length === 0) return t`Last name is required`;
|
||||
if (!/^[a-zA-Z\s]{2,20}$/.test(value))
|
||||
return "Last name must be 2-20 characters long and contain only letters";
|
||||
return t`Last name must be 2-20 characters long and contain only letters`;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -36,7 +39,7 @@ const NameUpdateForm = ({ player, toggle }: NameUpdateFormProps) => {
|
||||
await updatePlayer({ data }),
|
||||
onSuccess: toggle,
|
||||
onError: toggle,
|
||||
successMessage: "Name updated successfully!",
|
||||
successMessage: t`Name updated successfully!`,
|
||||
optimisticUpdate: (oldData, variables) => {
|
||||
if (!oldData) return oldData;
|
||||
return {
|
||||
@@ -61,13 +64,13 @@ const NameUpdateForm = ({ player, toggle }: NameUpdateFormProps) => {
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||
<Stack gap="xs">
|
||||
<TextInput label="First Name" {...form.getInputProps("first_name")} />
|
||||
<TextInput label="Last Name" {...form.getInputProps("last_name")} />
|
||||
<TextInput label={t`First Name`} {...form.getInputProps("first_name")} />
|
||||
<TextInput label={t`Last Name`} {...form.getInputProps("last_name")} />
|
||||
<Button loading={isPending} type="submit">
|
||||
Save
|
||||
<Trans>Save</Trans>
|
||||
</Button>
|
||||
<Button variant="subtle" color="red" onClick={toggle}>
|
||||
Cancel
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
|
||||
@@ -4,6 +4,7 @@ import TeamList from "@/features/teams/components/team-list";
|
||||
import { StatsSkeleton } from "@/components/stats-overview";
|
||||
import BadgeShowcaseSkeleton from "@/features/badges/components/badge-showcase-skeleton";
|
||||
import HeaderSkeleton from "./header-skeleton";
|
||||
import { useLingui } from "@lingui/react/macro";
|
||||
|
||||
const MatchCardSkeleton = ({ opacity = 1 }: { opacity?: number }) => (
|
||||
<Paper px="md" py="md" withBorder radius="md" style={{ opacity }}>
|
||||
@@ -58,17 +59,21 @@ const OverviewSkeleton = () => (
|
||||
);
|
||||
|
||||
const ProfileSkeleton = () => {
|
||||
const { t } = useLingui();
|
||||
const tabs = [
|
||||
{
|
||||
label: "Overview",
|
||||
label: t`Overview`,
|
||||
value: "overview",
|
||||
content: <OverviewSkeleton />,
|
||||
},
|
||||
{
|
||||
label: "Matches",
|
||||
label: t`Matches`,
|
||||
value: "matches",
|
||||
content: <MatchListSkeleton />,
|
||||
},
|
||||
{
|
||||
label: "Teams",
|
||||
label: t`Teams`,
|
||||
value: "teams",
|
||||
content: <TeamList teams={[]} loading />,
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user