-
Notifications
You must be signed in to change notification settings - Fork 446
Added entityName prop for custom labels #700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import { ProfilePage } from "./account-settings/profile-page/profile-page"; | |
import { SettingsPage } from './account-settings/settings/settings-page'; | ||
import { TeamCreationPage } from './account-settings/teams/team-creation-page'; | ||
import { TeamPage } from './account-settings/teams/team-page'; | ||
import { pluralize } from "pluralize"; | ||
|
||
const Icon = ({ name }: { name: keyof typeof icons }) => { | ||
const LucideIcon = icons[name]; | ||
|
@@ -23,6 +24,7 @@ const Icon = ({ name }: { name: keyof typeof icons }) => { | |
|
||
export function AccountSettings(props: { | ||
fullPage?: boolean, | ||
entityName?: string | ||
extraItems?: ({ | ||
title: string, | ||
content: React.ReactNode, | ||
|
@@ -38,6 +40,7 @@ export function AccountSettings(props: { | |
const teams = user.useTeams(); | ||
const stackApp = useStackApp(); | ||
const project = stackApp.useProject(); | ||
const entityName = props.entityName ?? "Team"; | ||
|
||
return ( | ||
<MaybeFullPage fullPage={!!props.fullPage}> | ||
|
@@ -101,7 +104,7 @@ export function AccountSettings(props: { | |
content: item.content, | ||
} as const)) || []), | ||
...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{ | ||
title: t('Teams'), | ||
title: t(`${pluralize(entityName)}`), | ||
type: 'divider', | ||
}] as const : [], | ||
...teams.map(team => ({ | ||
|
@@ -110,16 +113,16 @@ export function AccountSettings(props: { | |
<Typography className="max-w-[320px] md:w-[90%] truncate">{team.displayName}</Typography> | ||
</div>, | ||
type: 'item', | ||
id: `team-${team.id}`, | ||
id: `${entityName.toLowerCase()}-${team.id}`, | ||
content: <Suspense fallback={<TeamPageSkeleton/>}> | ||
<TeamPage team={team}/> | ||
</Suspense>, | ||
} as const)), | ||
...project.config.clientTeamCreationEnabled ? [{ | ||
title: t('Create a team'), | ||
title: t(`Create a ${entityName.toLowerCase()}`), | ||
icon: <Icon name="CirclePlus"/>, | ||
type: 'item', | ||
id: 'team-creation', | ||
id: `team-creation`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: ID still uses hardcoded 'team-creation' instead of entityName like other IDs |
||
content: <Suspense fallback={<TeamCreationSkeleton/>}> | ||
<TeamCreationPage /> | ||
</Suspense>, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,11 +12,15 @@ import { FormWarningText } from "../components/elements/form-warning"; | |
import { MaybeFullPage } from "../components/elements/maybe-full-page"; | ||
import { useTranslation } from "../lib/translations"; | ||
|
||
export function TeamCreation(props: { fullPage?: boolean }) { | ||
export function TeamCreation(props: { | ||
fullPage?: boolean, | ||
entityName?: string, | ||
}) { | ||
const { t } = useTranslation(); | ||
const entityName = props.entityName ? props.entityName : "Team"; | ||
|
||
const schema = yupObject({ | ||
displayName: yupString().defined().nonEmpty(t('Please enter a team name')), | ||
displayName: yupString().defined().nonEmpty(t(`Please enter ${entityName.toLowerCase()} name`)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Translation string with interpolation should use a translation key instead of direct interpolation to support proper localization |
||
}); | ||
|
||
const { register, handleSubmit, formState: { errors } } = useForm({ | ||
|
@@ -29,7 +33,7 @@ export function TeamCreation(props: { fullPage?: boolean }) { | |
const navigate = app.useNavigate(); | ||
|
||
if (!project.config.clientTeamCreationEnabled) { | ||
return <MessageCard title={t('Team creation is not enabled')} />; | ||
return <MessageCard title={t(`${entityName} creation is not enabled`)} />; | ||
} | ||
|
||
const onSubmit = async (data: yup.InferType<typeof schema>) => { | ||
|
@@ -48,7 +52,7 @@ export function TeamCreation(props: { fullPage?: boolean }) { | |
<div className='stack-scope flex flex-col items-stretch' style={{ maxWidth: '380px', flexBasis: '380px', padding: props.fullPage ? '1rem' : 0 }}> | ||
<div className="text-center mb-6"> | ||
<Typography type='h2'> | ||
{t('Create a Team')} | ||
{t(`Create ${entityName}`)} | ||
</Typography> | ||
</div> | ||
<form | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,11 +18,13 @@ import { Suspense, useEffect, useMemo } from "react"; | |
import { Team, useStackApp, useUser } from ".."; | ||
import { useTranslation } from "../lib/translations"; | ||
import { TeamIcon } from "./team-icon"; | ||
import { pluralize } from 'pluralize'; | ||
|
||
type SelectedTeamSwitcherProps = { | ||
urlMap?: (team: Team) => string, | ||
selectedTeam?: Team, | ||
noUpdateSelectedTeam?: boolean, | ||
entityName?: string, | ||
}; | ||
|
||
export function SelectedTeamSwitcher(props: SelectedTeamSwitcherProps) { | ||
|
@@ -44,6 +46,7 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
const selectedTeam = user?.selectedTeam || props.selectedTeam; | ||
const rawTeams = user?.useTeams(); | ||
const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]); | ||
const entityName = props.entityName ? props.entityName : "Team"; | ||
|
||
useEffect(() => { | ||
if (!props.noUpdateSelectedTeam && props.selectedTeam) { | ||
|
@@ -58,7 +61,7 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
runAsynchronouslyWithAlert(async () => { | ||
const team = teams?.find(team => team.id === value); | ||
if (!team) { | ||
throw new Error('Team not found, this should not happen'); | ||
throw new Error(`${entityName} not found, this should not happen`); | ||
} | ||
|
||
if (!props.noUpdateSelectedTeam) { | ||
|
@@ -71,14 +74,14 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
}} | ||
> | ||
<SelectTrigger className="stack-scope max-w-64"> | ||
<SelectValue placeholder="Select team"/> | ||
<SelectValue placeholder={`Select ${entityName.toLowerCase()}`}/> | ||
</SelectTrigger> | ||
<SelectContent className="stack-scope"> | ||
{user?.selectedTeam ? <SelectGroup> | ||
<SelectLabel> | ||
<div className="flex items-center justify-between"> | ||
<span> | ||
{t('Current team')} | ||
{t(`Current ${entityName.toLowerCase()}`)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Translation key uses string interpolation which may not work with all translation systems. Consider using a mapping of fixed keys instead. |
||
</span> | ||
<Button variant='ghost' size='icon' className="h-6 w-6" onClick={() => navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`)}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: URL path still uses hardcoded 'team-' prefix in #team-${user.selectedTeam?.id}. Should use entityName for consistency. |
||
<Settings className="h-4 w-4"/> | ||
|
@@ -95,7 +98,7 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
|
||
{teams?.length ? | ||
<SelectGroup> | ||
<SelectLabel>{t('Other teams')}</SelectLabel> | ||
<SelectLabel>{t(`Other ${pluralize(entityName.toLowerCase())}`)}</SelectLabel> | ||
{teams.filter(team => team.id !== user?.selectedTeam?.id) | ||
.map(team => ( | ||
<SelectItem value={team.id} key={team.id}> | ||
|
@@ -107,7 +110,7 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
))} | ||
</SelectGroup> : | ||
<SelectGroup> | ||
<SelectLabel>{t('No teams yet')}</SelectLabel> | ||
<SelectLabel>{t(`No ${pluralize(entityName.toLowerCase())} yet`)}</SelectLabel> | ||
</SelectGroup>} | ||
|
||
{project.config.clientTeamCreationEnabled && <> | ||
|
@@ -118,7 +121,7 @@ function Inner(props: SelectedTeamSwitcherProps) { | |
className="w-full" | ||
variant='ghost' | ||
> | ||
<PlusCircle className="mr-2 h-4 w-4"/> {t('Create a team')} | ||
<PlusCircle className="mr-2 h-4 w-4"/> {t(`Create ${entityName.toLowerCase()}`)} | ||
</Button> | ||
</div> | ||
</>} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: t() call with template literal could cause translation issues. Consider using t('plural_entity', {entity: entityName})