Add tag function in CreatePostPage
This commit is contained in:
74
client/src/components/NextUIFormikTagInput.tsx
Normal file
74
client/src/components/NextUIFormikTagInput.tsx
Normal 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;
|
||||
78
client/src/components/TagInput.tsx
Normal file
78
client/src/components/TagInput.tsx
Normal 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;
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user