input tags

This commit is contained in:
bflatastic committed 2024-10-03 19:53:26 +07:00
1 parent 954065b3e6
commit b2a67f095a
6 files changed
+212

No files matched your search

@@ -0,0 +1,21 @@
import MakeRequest from "../MakeRequest";
export interface EditTagsRequest {
tags: string;
}
export interface EditTagsResponse {
success: boolean;
tag_tokens: string[];
}
export const EditTags = MakeRequest<
string,
EditTagsRequest,
EditTagsResponse,
{}
>({
method: "POST",
routingFunction: (weight_token: string) =>
`/v1/tags/edit/model_weight/${weight_token}`,
});
@@ -0,0 +1,19 @@
import MakeRequest from "../MakeRequest";
export interface ListTagsRequest {}
export interface ListTagsResponse {
success: boolean;
tags: string[];
}
export const ListTags = MakeRequest<
string,
ListTagsRequest,
ListTagsResponse,
{}
>({
method: "GET",
routingFunction: (weight_token: string) =>
`/v1/tags/list/model_weight/${weight_token}`,
});
@@ -0,0 +1,63 @@
@import "scss/colours.scss";
.tags-input-container {
display: flex;
flex-wrap: wrap;
gap: 5px;
&:focus-within {
border-color: $primary;
outline: 0;
box-shadow: 0 0 0 0.1rem $primary;
}
}
.tag {
background-color: lighten($action, 10%);
border-radius: 5px;
padding: 0 8px;
display: flex;
align-items: center;
font-size: 15px;
gap: 8px;
}
.tag button {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
background: none;
border: none;
cursor: pointer;
color: rgba($white, 0.6);
transition: all 0.2s;
&:hover {
color: lighten($primary, 20%);
}
}
input[type="text"] {
border: none;
outline: none;
flex: 1;
background-color: transparent;
color: $white;
&::placeholder {
color: rgba($white, 0.5);
opacity: 1; /* Firefox */
}
&:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: rgba($white, 0.5);
}
&::-ms-input-placeholder {
/* Microsoft Edge */
color: rgba($white, 0.5);
}
}
@@ -0,0 +1,83 @@
import React, { useState } from "react";
import "./TagsInput.scss";
import Label from "../Label";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/pro-solid-svg-icons";
interface TagsInputProps {
value: string[];
label?: string;
onChange: (tags: string[]) => void;
className?: string;
tagsLimit?: number;
}
const TagsInput: React.FC<TagsInputProps> = ({
value,
label,
onChange,
className,
tagsLimit = Infinity,
}) => {
const [inputValue, setInputValue] = useState("");
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if ((event.key === "Enter" || event.key === ",") && inputValue.trim()) {
event.preventDefault();
addTag(inputValue);
} else if (event.key === "Backspace" && inputValue === "") {
handleRemoveTag(value.length - 1);
}
};
const handleBlur = () => {
if (inputValue.trim()) {
addTag(inputValue);
}
};
const addTag = (tag: string) => {
const lowerCaseValue = tag.trim().toLowerCase();
if (value.length < tagsLimit) {
onChange([...value, lowerCaseValue]);
setInputValue("");
} else {
setInputValue("");
}
};
const handleRemoveTag = (index: number) => {
const newTags = value.filter((_, i) => i !== index);
onChange(newTags);
};
return (
<div className={className}>
{label && <Label label={label} />}
<div className="tags-input-container form-control">
{value.map((tag, index) => (
<div className="tag" key={index}>
{tag}
<button type="button" onClick={() => handleRemoveTag(index)}>
<FontAwesomeIcon icon={faXmark} />
</button>
</div>
))}
<input
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
placeholder={
value.length < tagsLimit
? "Enter a tag and press Enter"
: "Tags limit reached"
}
/>
</div>
</div>
);
};
export default TagsInput;
@@ -9,6 +9,8 @@ import { UpdateWeight } from "@storyteller/components/src/api/weights/UpdateWeig
import { DeleteWeight } from "@storyteller/components/src/api/weights/DeleteWeight";
import { useCoverImgUpload } from "hooks";
import { LanguageTag } from "@storyteller/components/src/api/Languages";
import { ListTags } from "@storyteller/components/src/api/tags/ListTags";
import { EditTags } from "@storyteller/components/src/api/tags/EditTags";
interface Props {
onSuccess?: (res: Weight) => any;
@@ -32,6 +34,7 @@ export default function useWeightFetch({
const [maybeUrlSlug, maybeUrlSlugSet] = useState(undefined);
const [visibility, visibilitySet] = useState("public");
const [languageTag, languageTagSet] = useState<LanguageTag>("en" || null);
const [tags, tagsSet] = useState<string[]>([]);
const [descriptionMD, descriptionMDSet] = useState("");
const isLoading =
status === FetchStatus.ready || status === FetchStatus.in_progress;
@@ -64,6 +67,9 @@ export default function useWeightFetch({
weight_type: data?.weight_type || "",
})
.then((res: any) => {
EditTags(token, {
tags: tags.join(","),
});
writeStatusSet(FetchStatus.success);
history.replace(`/weight/${token}`);
})
@@ -93,6 +99,7 @@ export default function useWeightFetch({
descriptionMDSet("");
visibilitySet("public");
languageTagSet("en");
tagsSet([]);
}
}, [token, refetch]);
@@ -118,6 +125,12 @@ export default function useWeightFetch({
languageTagSet(maybe_ietf_primary_language_subtag);
onSuccess(res);
setData(res);
ListTags(token, {}).then((res: any) => {
if (res.success) {
tagsSet(res.tags);
}
});
} else {
statusSet(FetchStatus.error);
}
@@ -143,5 +156,7 @@ export default function useWeightFetch({
visibility,
writeStatus,
languageTag,
tags,
tagsSet,
};
}
@@ -24,6 +24,7 @@ import { useSession, useWeightFetch } from "hooks";
import "./WeightEditPage.scss";
import { LanguageLabels } from "@storyteller/components/src/api/Languages";
import { WeightCategory } from "@storyteller/components/src/api/_common/enums";
import TagsInput from "components/common/TagsInput/TagsInput";
export default function WeightEditPage() {
const { user, canEditTtsModel } = useSession();
@@ -45,6 +46,8 @@ export default function WeightEditPage() {
visibility,
languageTag,
writeStatus,
tags,
tagsSet,
// status
} = useWeightFetch({ token: weight_token });
@@ -180,6 +183,14 @@ export default function WeightEditPage() {
/>
)}
<TagsInput
label="Tags"
value={tags}
onChange={tagsSet}
className="mb-3"
tagsLimit={10}
/>
<TempSelect
{...{
icon: faEye,