Add tag function in CreatePostPage

This commit is contained in:
Rykkel
2024-08-10 18:23:23 +08:00
parent 196c9d875f
commit 5f59a046d6
3 changed files with 158 additions and 8 deletions

View File

@@ -0,0 +1,74 @@
import { Input } from "@nextui-org/react";
import { useField } from "formik";
import { useState } from "react";
import { EyeIcon, EyeSlashIcon } from "../icons";
interface NextUIFormikTagInputProps {
label: string;
name: string;
type: string;
placeholder: string;
labelPlacement?: "inside" | "outside";
startContent?: JSX.Element;
readOnly?: boolean;
setFieldValue?: (field: string, value: any, shouldValidate?: boolean) => void;
value?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; // Allow onChange prop
}
const NextUIFormikTagInput = ({
label,
startContent,
readOnly = false,
setFieldValue,
value,
onChange,
...props
}: NextUIFormikTagInputProps) => {
// Use Formik's useField hook to get field props and meta information
const [field, meta] = useField(props.name);
const [inputType, setInputType] = useState(props.type);
// Handle changes in the input field
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
field.onChange(e);
if (setFieldValue) {
setFieldValue(props.name, value);
}
if (onChange) {
onChange(e); // Call the passed onChange handler
}
};
return (
<Input
{...field}
{...props}
label={label}
type={inputType}
isInvalid={meta.touched && !!meta.error}
errorMessage={meta.touched && meta.error ? meta.error : ""}
startContent={startContent}
endContent={
props.type === "password" ? (
<>
<button
type="button"
onClick={() => {
setInputType(inputType === "text" ? "password" : "text");
}}
>
{inputType === "password" ? <EyeSlashIcon /> : <EyeIcon />}
</button>
</>
) : null
}
readOnly={readOnly}
onChange={handleChange}
value={value} // Ensure the value from Formik is applied to the input
/>
);
};
export default NextUIFormikTagInput;

View File

@@ -0,0 +1,78 @@
import React, { useState } from "react";
import { Button, input } from "@nextui-org/react";
import NextUIFormikTagInput from "./NextUIFormikTagInput";
type TagInputProps = {
tags: string[];
setTags: React.Dispatch<React.SetStateAction<string[]>>;
};
const TagInput: React.FC<TagInputProps> = ({ tags, setTags }) => {
const [inputTag, setInputTag] = useState("");
const [error, setError] = useState<string | null>(null);
// Handle input change and dynamic duplicate check
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTag = e.target.value.trim();
setInputTag(newTag);
// Dynamic duplicate check
if (tags.some(tag => tag.toLowerCase() === newTag.toLowerCase())) {
setError("Tag already added.");
} else {
setError(null);
}
};
const handleAddTag = () => {
if (error) {
return; // Prevent adding if there's an error
}
if (inputTag.trim() !== "") {
setTags([...tags, inputTag.trim()]);
setInputTag(""); // Clear input field
}
};
const handleRemoveTag = (index: number) => {
setTags(tags.filter((_, i) => i !== index));
};
return (
<div>
<div>
<NextUIFormikTagInput
label="Tags (Optional)"
name="tagInput" // This name should be unique and not conflict with other form fields
type="text"
placeholder="Enter tags"
labelPlacement="inside"
value={inputTag}
onChange={handleInputChange} // Use the dynamic check handler
/>
{error && <div className="text-red-500 mt-2">{error}</div>}
<Button onPress={handleAddTag} disabled={!!error}>Add</Button>
</div>
<div className="flex gap-2 flex-wrap mt-4">
{tags.map((tag, index) => (
<div
key={index}
className="flex items-center gap-1 bg-gray-200 p-2 rounded"
>
<span>{tag}</span>
<button
type="button"
onClick={() => handleRemoveTag(index)}
className="ml-2 text-red-500"
>
X
</button>
</div>
))}
</div>
</div>
);
};
export default TagInput;

View File

@@ -10,6 +10,7 @@ import { ArrowUTurnLeftIcon } from "../icons";
import { useEffect, useState } from "react";
import { retrieveUserInformation } from "../security/users";
import InsertPostImage from "../components/InsertPostImage";
import TagInput from "../components/TagInput";
const validationSchema = Yup.object({
title: Yup.string()
@@ -37,6 +38,7 @@ function CreatePostPage() {
const navigate = useNavigate();
const [userId, setUserId] = useState(null);
// Add state for image selection
const [tags, setTags] = useState<string[]>([]);
const initialValues = {
title: "",
@@ -69,7 +71,8 @@ function CreatePostPage() {
if (values.postImage) {
formData.append("postImage", values.postImage);
}
formData.append("tags", values.tags);
// formData.append("tags", values.tags);
formData.append("tags", tags.join(","));
formData.append("userId", userId || ""); // Ensure userId is appended to formData
console.log("Submitting formData:", formData);
@@ -83,6 +86,7 @@ function CreatePostPage() {
if (response.status === 200) {
console.log("Post created successfully:", response.data);
resetForm(); // Clear form after successful submit
setTags([]);
setFieldValue("postImage", null);
navigate(-1);
} else {
@@ -136,13 +140,7 @@ function CreatePostPage() {
/>
</div>
<div>
<NextUIFormikInput
label="Tags (Optional)"
name="tags"
type="text"
placeholder="Enter tags"
labelPlacement="inside"
/>
<TagInput tags={tags} setTags={setTags} />
</div>
<div className="text-sm">
<div className="flex flex-row gap-10">