Skip to content

Commit

Permalink
feat(translation): crud language
Browse files Browse the repository at this point in the history
  • Loading branch information
matedocebo committed Feb 27, 2024
1 parent 1a128bb commit ab150e3
Show file tree
Hide file tree
Showing 11 changed files with 361 additions and 19 deletions.
5 changes: 4 additions & 1 deletion app/api/translations/[translationId]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ const routeContextSchema = z.object({
}),
})

export async function DELETE(context: z.infer<typeof routeContextSchema>) {
export async function DELETE(
_req: Request,
context: z.infer<typeof routeContextSchema>
) {
try {
// Validate the route params.
const { params } = routeContextSchema.parse(context)
Expand Down
6 changes: 1 addition & 5 deletions components/slide-over.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,7 @@ export type SlideOverButtonProps = {
}

export const SlideOverButton = (props: SlideOverButtonProps) => (
<button
type="button"
onClick={props.onClick}
className="max-w-max py-2 px-3 inline-flex items-center gap-x-2 text-[13px] font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-white dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600"
>
<button type="button" onClick={props.onClick} className="t-button">
<svg
className="shrink-0 size-4"
xmlns="http://www.w3.org/2000/svg"
Expand Down
118 changes: 118 additions & 0 deletions components/translation/dialogs/add-edit-languages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { ChangeEvent, useCallback, useState } from "react"
import { EditLanguageType, Language } from "@/store/useI18nState"
import { DialogClose } from "@radix-ui/react-dialog"

import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

type Props = {
language: Language
editLanguage: (language: EditLanguageType) => void
deleteLanguage: (language: Language) => void
}

const EditLanguage = (props: Props) => {
const { language, editLanguage, deleteLanguage } = props

const [languageName, setLanguageName] = useState(language.lang)
const [shortName, setShortName] = useState(language.short)

const handleChangeLanguageName = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setLanguageName(e.target.value)
},
[]
)

const handleChangeShortName = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setShortName(e.target.value)
},
[]
)

const reset = useCallback(() => {
setLanguageName("")
setShortName("")
}, [])

const onSubmit = useCallback(() => {
editLanguage({
exShortName: language.short,
lang: languageName,
short: shortName,
})
reset()
}, [editLanguage, language.short, languageName, reset, shortName])

return (
<Dialog>
<DialogTrigger asChild>
<button className="t-button">
[{language.short}] {language.lang}
</button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit language: {language.lang}</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input
id="languageName"
placeholder="English"
className="col-span-3"
data-1p-ignore
value={languageName}
onChange={handleChangeLanguageName}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Short name (filename)
</Label>
<Input
id="shortName"
placeholder="en"
className="col-span-3"
data-1p-ignore
value={shortName}
onChange={handleChangeShortName}
/>
</div>
</div>
<DialogFooter className="sm:justify-between">
<DialogClose asChild>
<Button
type="button"
variant="destructive"
className="mt-4 sm:mt-0"
onClick={() => {
deleteLanguage(language)
}}
>
Delete
</Button>
</DialogClose>
<DialogClose asChild>
<Button onClick={onSubmit}>Edit language</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
)
}

export default EditLanguage
116 changes: 116 additions & 0 deletions components/translation/dialogs/add-new-languages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { ChangeEvent, useCallback, useState } from "react"
import { Language } from "@/store/useI18nState"
import { DialogClose } from "@radix-ui/react-dialog"

import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

type Props = {
addLanguage: (language: Language) => void
}

const AddNewLanguage = (props: Props) => {
const { addLanguage } = props

const [languageName, setLanguageName] = useState("")
const [shortName, setShortName] = useState("")

const handleChangeLanguageName = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setLanguageName(e.target.value)
},
[]
)

const handleChangeShortName = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setShortName(e.target.value)
},
[]
)

const reset = useCallback(() => {
setLanguageName("")
setShortName("")
}, [])

const onSubmit = useCallback(() => {
addLanguage({
lang: languageName,
short: shortName,
})
reset()
}, [addLanguage, languageName, reset, shortName])

return (
<Dialog>
<DialogTrigger asChild>
<button className="t-button">
<svg
className="h-3.5 w-3.5"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
clipRule="evenodd"
fillRule="evenodd"
d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z"
/>
</svg>
Add language
</button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>New language</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input
id="languageName"
placeholder="English"
className="col-span-3"
data-1p-ignore
value={languageName}
onChange={handleChangeLanguageName}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Short name (filename)
</Label>
<Input
id="shortName"
placeholder="en"
className="col-span-3"
data-1p-ignore
value={shortName}
onChange={handleChangeShortName}
/>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button onClick={onSubmit}>Add language</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
)
}

export default AddNewLanguage
12 changes: 11 additions & 1 deletion components/translation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ export function Editor(props: EditorProps) {
keywords,
isSaving,
title,
languages,
save,
addNewKey,
deleteKey,
editTranslation,
setTitle,
editContext,
addLanguage,
editLanguage,
deleteLanguage,
} = useTranslation(props)

const [isProjectSettingsOpened, openProjectSettings] =
Expand Down Expand Up @@ -85,7 +89,13 @@ export function Editor(props: EditorProps) {
/>
</div>
{isProjectSettingsOpened && (
<ProjectSettingsSlideOver onClose={() => openProjectSettings(false)} />
<ProjectSettingsSlideOver
languages={languages}
addLanguage={addLanguage}
editLanguage={editLanguage}
deleteLanguage={deleteLanguage}
onClose={() => openProjectSettings(false)}
/>
)}
</div>
)
Expand Down
33 changes: 30 additions & 3 deletions components/translation/settings-slide-over.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
import { EditLanguageType, Language } from "@/store/useI18nState"

import SlideOver, { SlideOverButton, SlideOverRow } from "../slide-over"
import EditLanguage from "./dialogs/add-edit-languages"
import AddNewLanguage from "./dialogs/add-new-languages"

type Props = {
languages: Language[]
addLanguage: (language: Language) => void
editLanguage: (language: EditLanguageType) => void
deleteLanguage: (language: Language) => void
onClose: () => void
}

const ProjectSettingsSlideOver = (props: Props) => {
const { onClose } = props
const { languages, addLanguage, editLanguage, deleteLanguage, onClose } =
props

{
languages.map((language) => (
<button key={language.short} type="button" className="t-button">
[{language.short}] {language.lang}
</button>
))
}
return (
<SlideOver title="Settings" onClose={onClose} onSave={() => {}}>
<SlideOver title="Settings" onClose={onClose}>
<div className="relative p-4 flex-1 sm:px-6">
<SlideOverRow title="Available languages">
<SlideOverButton text="Add language" onClick={() => {}} />
<>
{languages.map((language) => (
<EditLanguage
key={language.short}
language={language}
editLanguage={editLanguage}
deleteLanguage={deleteLanguage}
/>
))}
</>

<AddNewLanguage addLanguage={addLanguage} />
</SlideOverRow>
</div>
<div className="relative p-4 flex-1 sm:px-6">
Expand Down
4 changes: 2 additions & 2 deletions components/translation/table/row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const Row = (props: Props) => {
key={language.language}
className="text-green-600 dark:text-green-500 font-medium"
>
{language.language.toUpperCase()}
{language.short.toUpperCase()}
</span>
)
}
Expand All @@ -41,7 +41,7 @@ const Row = (props: Props) => {
key={language.language}
className="text-red-600 dark:text-red-500 font-medium"
>
{language.language.toUpperCase()}
{language.short.toUpperCase()}
</span>
)
})}
Expand Down
Loading

0 comments on commit ab150e3

Please sign in to comment.