Extract inline forms from CategorySection into separate components
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import { Button, Input, Td, Tr } from "@probo/ui";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import type { CookieEntry } from "./CategorySection";
|
||||||
|
|
||||||
|
interface AddCookieRowProps {
|
||||||
|
isUpdating: boolean;
|
||||||
|
onSave: (cookie: CookieEntry) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddCookieRow({
|
||||||
|
isUpdating,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
}: AddCookieRowProps) {
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const [form, setForm] = useState<CookieEntry>({
|
||||||
|
name: "",
|
||||||
|
duration: "",
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tr>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.name}
|
||||||
|
onChange={e => setForm({ ...form, name: e.target.value })}
|
||||||
|
placeholder={__("Cookie name")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.duration}
|
||||||
|
onChange={e => setForm({ ...form, duration: e.target.value })}
|
||||||
|
placeholder={__("e.g. 1 year")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.description}
|
||||||
|
onChange={e => setForm({ ...form, description: e.target.value })}
|
||||||
|
placeholder={__("Description")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
onClick={() => onSave(form)}
|
||||||
|
disabled={isUpdating}
|
||||||
|
>
|
||||||
|
{__("Save")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onCancel}
|
||||||
|
>
|
||||||
|
{__("Cancel")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -24,10 +24,8 @@ import {
|
|||||||
IconPencil,
|
IconPencil,
|
||||||
IconPlusSmall,
|
IconPlusSmall,
|
||||||
IconTrashCan,
|
IconTrashCan,
|
||||||
Input,
|
|
||||||
Tbody,
|
Tbody,
|
||||||
Td,
|
Td,
|
||||||
Textarea,
|
|
||||||
Th,
|
Th,
|
||||||
Thead,
|
Thead,
|
||||||
Tr,
|
Tr,
|
||||||
@@ -41,6 +39,16 @@ import type { CategorySectionFragment$key } from "#/__generated__/core/CategoryS
|
|||||||
import type { CategorySectionMoveCookieMutation } from "#/__generated__/core/CategorySectionMoveCookieMutation.graphql";
|
import type { CategorySectionMoveCookieMutation } from "#/__generated__/core/CategorySectionMoveCookieMutation.graphql";
|
||||||
import type { CategorySectionUpdateMutation } from "#/__generated__/core/CategorySectionUpdateMutation.graphql";
|
import type { CategorySectionUpdateMutation } from "#/__generated__/core/CategorySectionUpdateMutation.graphql";
|
||||||
|
|
||||||
|
import { AddCookieRow } from "./AddCookieRow";
|
||||||
|
import { EditCategoryForm } from "./EditCategoryForm";
|
||||||
|
import { EditCookieRow } from "./EditCookieRow";
|
||||||
|
|
||||||
|
export interface CookieEntry {
|
||||||
|
name: string;
|
||||||
|
duration: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const categorySectionFragment = graphql`
|
export const categorySectionFragment = graphql`
|
||||||
fragment CategorySectionFragment on CookieCategory {
|
fragment CategorySectionFragment on CookieCategory {
|
||||||
id
|
id
|
||||||
@@ -134,12 +142,6 @@ const moveCookieMutation = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface CookieEntry {
|
|
||||||
name: string;
|
|
||||||
duration: string;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CategorySectionProps {
|
interface CategorySectionProps {
|
||||||
categoryKey: CategorySectionFragment$key;
|
categoryKey: CategorySectionFragment$key;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
@@ -156,18 +158,8 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
= useMutation<CategorySectionMoveCookieMutation>(moveCookieMutation);
|
= useMutation<CategorySectionMoveCookieMutation>(moveCookieMutation);
|
||||||
|
|
||||||
const [isEditingCategory, setIsEditingCategory] = useState(false);
|
const [isEditingCategory, setIsEditingCategory] = useState(false);
|
||||||
const [editName, setEditName] = useState(category.name);
|
const [editingCookieIndex, setEditingCookieIndex] = useState<number | null>(null);
|
||||||
const [editDescription, setEditDescription] = useState(category.description);
|
|
||||||
|
|
||||||
const [editingCookieIndex, setEditingCookieIndex] = useState<number | null>(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const [isAddingCookie, setIsAddingCookie] = useState(false);
|
const [isAddingCookie, setIsAddingCookie] = useState(false);
|
||||||
const [cookieForm, setCookieForm] = useState<CookieEntry>({
|
|
||||||
name: "",
|
|
||||||
duration: "",
|
|
||||||
description: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const doUpdate = (
|
const doUpdate = (
|
||||||
input: Record<string, unknown>,
|
input: Record<string, unknown>,
|
||||||
@@ -209,48 +201,24 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveCategory = () => {
|
const handleSaveCategory = (name: string, description: string) => {
|
||||||
doUpdate({ name: editName, description: editDescription }, () => {
|
doUpdate({ name, description }, () => {
|
||||||
setIsEditingCategory(false);
|
setIsEditingCategory(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelCategoryEdit = () => {
|
const handleSaveEditCookie = (index: number, cookie: CookieEntry) => {
|
||||||
setEditName(category.name);
|
if (!cookie.name.trim()) return;
|
||||||
setEditDescription(category.description);
|
|
||||||
setIsEditingCategory(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStartEditCookie = (index: number) => {
|
|
||||||
const c = category.cookies[index];
|
|
||||||
setCookieForm({
|
|
||||||
name: c.name,
|
|
||||||
duration: c.duration,
|
|
||||||
description: c.description,
|
|
||||||
});
|
|
||||||
setEditingCookieIndex(index);
|
|
||||||
setIsAddingCookie(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveEditCookie = () => {
|
|
||||||
if (editingCookieIndex === null) return;
|
|
||||||
if (!cookieForm.name.trim()) return;
|
|
||||||
const newCookies = category.cookies.map((c, i) =>
|
const newCookies = category.cookies.map((c, i) =>
|
||||||
i === editingCookieIndex
|
i === index
|
||||||
? { ...cookieForm }
|
? { ...cookie }
|
||||||
: { name: c.name, duration: c.duration, description: c.description },
|
: { name: c.name, duration: c.duration, description: c.description },
|
||||||
);
|
);
|
||||||
doUpdate({ cookies: newCookies }, () => {
|
doUpdate({ cookies: newCookies }, () => {
|
||||||
setEditingCookieIndex(null);
|
setEditingCookieIndex(null);
|
||||||
setCookieForm({ name: "", duration: "", description: "" });
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelEditCookie = () => {
|
|
||||||
setEditingCookieIndex(null);
|
|
||||||
setCookieForm({ name: "", duration: "", description: "" });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteCookie = (index: number) => {
|
const handleDeleteCookie = (index: number) => {
|
||||||
const newCookies = category.cookies
|
const newCookies = category.cookies
|
||||||
.filter((_, i) => i !== index)
|
.filter((_, i) => i !== index)
|
||||||
@@ -262,33 +230,21 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
doUpdate({ cookies: newCookies });
|
doUpdate({ cookies: newCookies });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartAddCookie = () => {
|
const handleSaveNewCookie = (cookie: CookieEntry) => {
|
||||||
setCookieForm({ name: "", duration: "", description: "" });
|
if (!cookie.name.trim()) return;
|
||||||
setIsAddingCookie(true);
|
|
||||||
setEditingCookieIndex(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveNewCookie = () => {
|
|
||||||
if (!cookieForm.name.trim()) return;
|
|
||||||
const newCookies = [
|
const newCookies = [
|
||||||
...category.cookies.map(c => ({
|
...category.cookies.map(c => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
duration: c.duration,
|
duration: c.duration,
|
||||||
description: c.description,
|
description: c.description,
|
||||||
})),
|
})),
|
||||||
{ ...cookieForm },
|
{ ...cookie },
|
||||||
];
|
];
|
||||||
doUpdate({ cookies: newCookies }, () => {
|
doUpdate({ cookies: newCookies }, () => {
|
||||||
setIsAddingCookie(false);
|
setIsAddingCookie(false);
|
||||||
setCookieForm({ name: "", duration: "", description: "" });
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelAddCookie = () => {
|
|
||||||
setIsAddingCookie(false);
|
|
||||||
setCookieForm({ name: "", duration: "", description: "" });
|
|
||||||
};
|
|
||||||
|
|
||||||
const allCategories = category.cookieBanner.categories.edges.map(e => e.node) ?? [];
|
const allCategories = category.cookieBanner.categories.edges.map(e => e.node) ?? [];
|
||||||
const siblingCategories = allCategories.filter(c => c.id !== category.id);
|
const siblingCategories = allCategories.filter(c => c.id !== category.id);
|
||||||
|
|
||||||
@@ -336,33 +292,13 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
{isEditingCategory
|
{isEditingCategory
|
||||||
? (
|
? (
|
||||||
<div className="space-y-3">
|
<EditCategoryForm
|
||||||
<Input
|
name={category.name}
|
||||||
value={editName}
|
description={category.description}
|
||||||
onChange={e => setEditName(e.target.value)}
|
isUpdating={isUpdating}
|
||||||
placeholder={__("Category name")}
|
onSave={handleSaveCategory}
|
||||||
/>
|
onCancel={() => setIsEditingCategory(false)}
|
||||||
<Textarea
|
/>
|
||||||
value={editDescription}
|
|
||||||
onChange={e => setEditDescription(e.target.value)}
|
|
||||||
placeholder={__("Category description")}
|
|
||||||
rows={2}
|
|
||||||
/>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button
|
|
||||||
onClick={handleSaveCategory}
|
|
||||||
disabled={isUpdating}
|
|
||||||
>
|
|
||||||
{isUpdating ? __("Saving...") : __("Save")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={handleCancelCategoryEdit}
|
|
||||||
>
|
|
||||||
{__("Cancel")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -420,54 +356,17 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
{category.cookies.map((cookie, index) =>
|
{category.cookies.map((cookie, index) =>
|
||||||
editingCookieIndex === index
|
editingCookieIndex === index
|
||||||
? (
|
? (
|
||||||
<Tr key={index}>
|
<EditCookieRow
|
||||||
<Td className="pr-3">
|
key={index}
|
||||||
<Input
|
cookie={{
|
||||||
value={cookieForm.name}
|
name: cookie.name,
|
||||||
onChange={e =>
|
duration: cookie.duration,
|
||||||
setCookieForm({ ...cookieForm, name: e.target.value })}
|
description: cookie.description,
|
||||||
placeholder={__("Cookie name")}
|
}}
|
||||||
/>
|
isUpdating={isUpdating}
|
||||||
</Td>
|
onSave={updated => handleSaveEditCookie(index, updated)}
|
||||||
<Td className="pr-3">
|
onCancel={() => setEditingCookieIndex(null)}
|
||||||
<Input
|
/>
|
||||||
value={cookieForm.duration}
|
|
||||||
onChange={e =>
|
|
||||||
setCookieForm({
|
|
||||||
...cookieForm,
|
|
||||||
duration: e.target.value,
|
|
||||||
})}
|
|
||||||
placeholder={__("e.g. 1 year")}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td className="pr-3">
|
|
||||||
<Input
|
|
||||||
value={cookieForm.description}
|
|
||||||
onChange={e =>
|
|
||||||
setCookieForm({
|
|
||||||
...cookieForm,
|
|
||||||
description: e.target.value,
|
|
||||||
})}
|
|
||||||
placeholder={__("Description")}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
<Button
|
|
||||||
onClick={handleSaveEditCookie}
|
|
||||||
disabled={isUpdating}
|
|
||||||
>
|
|
||||||
{__("Save")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={handleCancelEditCookie}
|
|
||||||
>
|
|
||||||
{__("Cancel")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<Tr key={index}>
|
<Tr key={index}>
|
||||||
@@ -484,7 +383,10 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleStartEditCookie(index)}
|
onClick={() => {
|
||||||
|
setEditingCookieIndex(index);
|
||||||
|
setIsAddingCookie(false);
|
||||||
|
}}
|
||||||
className="p-1 rounded cursor-pointer"
|
className="p-1 rounded cursor-pointer"
|
||||||
>
|
>
|
||||||
<IconPencil size={14} />
|
<IconPencil size={14} />
|
||||||
@@ -524,51 +426,11 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
{isAddingCookie && (
|
{isAddingCookie && (
|
||||||
<Tr>
|
<AddCookieRow
|
||||||
<Td className="pr-3">
|
isUpdating={isUpdating}
|
||||||
<Input
|
onSave={handleSaveNewCookie}
|
||||||
value={cookieForm.name}
|
onCancel={() => setIsAddingCookie(false)}
|
||||||
onChange={e =>
|
/>
|
||||||
setCookieForm({ ...cookieForm, name: e.target.value })}
|
|
||||||
placeholder={__("Cookie name")}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td className="pr-3">
|
|
||||||
<Input
|
|
||||||
value={cookieForm.duration}
|
|
||||||
onChange={e =>
|
|
||||||
setCookieForm({ ...cookieForm, duration: e.target.value })}
|
|
||||||
placeholder={__("e.g. 1 year")}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td className="pr-3">
|
|
||||||
<Input
|
|
||||||
value={cookieForm.description}
|
|
||||||
onChange={e =>
|
|
||||||
setCookieForm({
|
|
||||||
...cookieForm,
|
|
||||||
description: e.target.value,
|
|
||||||
})}
|
|
||||||
placeholder={__("Description")}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button
|
|
||||||
onClick={handleSaveNewCookie}
|
|
||||||
disabled={isUpdating}
|
|
||||||
>
|
|
||||||
{__("Save")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={handleCancelAddCookie}
|
|
||||||
>
|
|
||||||
{__("Cancel")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
)}
|
)}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -577,7 +439,10 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
|||||||
<div className="p-3 border-t border-border-low">
|
<div className="p-3 border-t border-border-low">
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={handleStartAddCookie}
|
onClick={() => {
|
||||||
|
setIsAddingCookie(true);
|
||||||
|
setEditingCookieIndex(null);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<IconPlusSmall size={14} />
|
<IconPlusSmall size={14} />
|
||||||
{__("Add Cookie")}
|
{__("Add Cookie")}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import { Button, Input, Textarea } from "@probo/ui";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
interface EditCategoryFormProps {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
isUpdating: boolean;
|
||||||
|
onSave: (name: string, description: string) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EditCategoryForm({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
isUpdating,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
}: EditCategoryFormProps) {
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const [editName, setEditName] = useState(name);
|
||||||
|
const [editDescription, setEditDescription] = useState(description);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Input
|
||||||
|
value={editName}
|
||||||
|
onChange={e => setEditName(e.target.value)}
|
||||||
|
placeholder={__("Category name")}
|
||||||
|
/>
|
||||||
|
<Textarea
|
||||||
|
value={editDescription}
|
||||||
|
onChange={e => setEditDescription(e.target.value)}
|
||||||
|
placeholder={__("Category description")}
|
||||||
|
rows={2}
|
||||||
|
/>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
onClick={() => onSave(editName, editDescription)}
|
||||||
|
disabled={isUpdating}
|
||||||
|
>
|
||||||
|
{isUpdating ? __("Saving...") : __("Save")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onCancel}
|
||||||
|
>
|
||||||
|
{__("Cancel")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import { Button, Input, Td, Tr } from "@probo/ui";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import type { CookieEntry } from "./CategorySection";
|
||||||
|
|
||||||
|
interface EditCookieRowProps {
|
||||||
|
cookie: CookieEntry;
|
||||||
|
isUpdating: boolean;
|
||||||
|
onSave: (cookie: CookieEntry) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EditCookieRow({
|
||||||
|
cookie,
|
||||||
|
isUpdating,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
}: EditCookieRowProps) {
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const [form, setForm] = useState<CookieEntry>(cookie);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tr>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.name}
|
||||||
|
onChange={e => setForm({ ...form, name: e.target.value })}
|
||||||
|
placeholder={__("Cookie name")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.duration}
|
||||||
|
onChange={e => setForm({ ...form, duration: e.target.value })}
|
||||||
|
placeholder={__("e.g. 1 year")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td className="pr-3">
|
||||||
|
<Input
|
||||||
|
value={form.description}
|
||||||
|
onChange={e => setForm({ ...form, description: e.target.value })}
|
||||||
|
placeholder={__("Description")}
|
||||||
|
/>
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Button
|
||||||
|
onClick={() => onSave(form)}
|
||||||
|
disabled={isUpdating}
|
||||||
|
>
|
||||||
|
{__("Save")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onCancel}
|
||||||
|
>
|
||||||
|
{__("Cancel")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user