From f2efb0234949517b552c0d0d74822407acfa81b5 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Tue, 18 Feb 2025 11:30:21 -0500 Subject: [PATCH 01/10] chore: replaces baseformpage --- .../components/forms/VoyageSubmissionForm.tsx | 2 +- .../components/forms/WeeklyCheckInForm.tsx | 2 +- src/components/form/BaseFormPage.tsx | 20 ------------------- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 src/components/form/BaseFormPage.tsx diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/VoyageSubmissionForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/VoyageSubmissionForm.tsx index 087e990a6..950bdc428 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/VoyageSubmissionForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/VoyageSubmissionForm.tsx @@ -7,7 +7,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import BaseFormPage from "@/components/form/BaseFormPage"; +import { BaseFormPage } from "@chingu-x/components/form"; import { submitVoyageProjectForm } from "@/myVoyage/sprints/sprintsService"; import FormInput from "@/components/form/FormInput"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/WeeklyCheckInForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/WeeklyCheckInForm.tsx index a7846bf8a..d026b82ce 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/WeeklyCheckInForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/WeeklyCheckInForm.tsx @@ -7,7 +7,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import BaseFormPage from "@/components/form/BaseFormPage"; +import { BaseFormPage } from "@chingu-x/components/form"; import { submitCheckInForm } from "@/myVoyage/sprints/sprintsService"; import FormInput from "@/components/form/FormInput"; diff --git a/src/components/form/BaseFormPage.tsx b/src/components/form/BaseFormPage.tsx deleted file mode 100644 index c959f13fd..000000000 --- a/src/components/form/BaseFormPage.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import FormBanner from "./FormBanner"; - -interface BaseFormPageProps { - title: string; - description: string; - children: React.ReactNode; -} - -export default function BaseFormPage({ - title, - description, - children, -}: BaseFormPageProps) { - return ( -
- - {children} -
- ); -} From 7a3ec5095ab8c9c9393ae763750b98004f73d0b3 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Tue, 18 Feb 2025 11:31:56 -0500 Subject: [PATCH 02/10] chore: removed formbanner --- src/components/form/FormBanner.tsx | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/components/form/FormBanner.tsx diff --git a/src/components/form/FormBanner.tsx b/src/components/form/FormBanner.tsx deleted file mode 100644 index 0cbbd9d00..000000000 --- a/src/components/form/FormBanner.tsx +++ /dev/null @@ -1,15 +0,0 @@ -interface FormBannerProps { - title: string; - description: string; -} - -export default function FormBanner({ title, description }: FormBannerProps) { - return ( -
-
-

{title}

-

{description}

-
-
- ); -} From 795b7a4c24a72866822e0bfdbe77d1948d13ab0e Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Tue, 18 Feb 2025 11:42:13 -0500 Subject: [PATCH 03/10] chore: replaced textinput --- .../components/ResetPasswordContainer.tsx | 2 +- .../components/SignInFormContainer.tsx | 2 +- .../components/SignUpFormContainer.tsx | 2 +- .../users/components/NewPasswordContainer.tsx | 2 +- .../directory/components/EditHours.tsx | 2 +- .../features/components/AddFeaturesInput.tsx | 2 +- .../[teamId]/features/components/ListItem.tsx | 2 +- .../ideation/components/IdeationForm.tsx | 2 +- .../components/forms/AgendaTopicForm.tsx | 2 +- .../sprints/components/forms/MeetingForm.tsx | 2 +- .../tech-stack/components/TechStackCard.tsx | 2 +- .../components/ResourceInput.tsx | 2 +- src/components/form/FormInput.tsx | 2 +- src/components/inputs/TextInput.tsx | 178 ---------------- .../components/inputs/TextInput.stories.tsx | 190 ------------------ 15 files changed, 13 insertions(+), 381 deletions(-) delete mode 100644 src/components/inputs/TextInput.tsx delete mode 100644 src/stories/components/inputs/TextInput.stories.tsx diff --git a/src/app/(auth)/sign-in/components/ResetPasswordContainer.tsx b/src/app/(auth)/sign-in/components/ResetPasswordContainer.tsx index a68217796..3581c2008 100644 --- a/src/app/(auth)/sign-in/components/ResetPasswordContainer.tsx +++ b/src/app/(auth)/sign-in/components/ResetPasswordContainer.tsx @@ -5,8 +5,8 @@ import { type SubmitHandler, useForm } from "react-hook-form"; import { type Dispatch, type SetStateAction } from "react"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import { resetPasswordRequestEmail } from "@/app/(auth)/authService"; -import TextInput from "@/components/inputs/TextInput"; import { onOpenModal } from "@/store/features/modal/modalSlice"; import { useAppDispatch } from "@/store/hooks"; import { validateTextInput } from "@/utils/form/validateInput"; diff --git a/src/app/(auth)/sign-in/components/SignInFormContainer.tsx b/src/app/(auth)/sign-in/components/SignInFormContainer.tsx index 9f4518c3c..1372915b7 100644 --- a/src/app/(auth)/sign-in/components/SignInFormContainer.tsx +++ b/src/app/(auth)/sign-in/components/SignInFormContainer.tsx @@ -5,9 +5,9 @@ import { type SubmitHandler, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import { serverSignIn } from "@/app/(auth)/authService"; -import TextInput from "@/components/inputs/TextInput"; import { validateTextInput } from "@/utils/form/validateInput"; import { clientSignIn } from "@/store/features/auth/authSlice"; import { onOpenModal } from "@/store/features/modal/modalSlice"; diff --git a/src/app/(auth)/sign-up/components/SignUpFormContainer.tsx b/src/app/(auth)/sign-up/components/SignUpFormContainer.tsx index 6923a0e46..ea0154825 100644 --- a/src/app/(auth)/sign-up/components/SignUpFormContainer.tsx +++ b/src/app/(auth)/sign-up/components/SignUpFormContainer.tsx @@ -3,7 +3,7 @@ import { useForm, type SubmitHandler } from "react-hook-form"; import * as z from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@chingu-x/components/button"; -import TextInput from "@/components/inputs/TextInput"; +import { TextInput } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import routePaths from "@/utils/routePaths"; diff --git a/src/app/(auth)/users/components/NewPasswordContainer.tsx b/src/app/(auth)/users/components/NewPasswordContainer.tsx index 4f46a95f2..9e6b77540 100644 --- a/src/app/(auth)/users/components/NewPasswordContainer.tsx +++ b/src/app/(auth)/users/components/NewPasswordContainer.tsx @@ -4,8 +4,8 @@ import * as z from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import { resetPassword } from "@/app/(auth)/authService"; -import TextInput from "@/components/inputs/TextInput"; import { onOpenModal } from "@/store/features/modal/modalSlice"; import { useAppDispatch } from "@/store/hooks"; import { validateTextInput } from "@/utils/form/validateInput"; diff --git a/src/app/(main)/my-voyage/[teamId]/directory/components/EditHours.tsx b/src/app/(main)/my-voyage/[teamId]/directory/components/EditHours.tsx index 88996120d..66fce2d28 100644 --- a/src/app/(main)/my-voyage/[teamId]/directory/components/EditHours.tsx +++ b/src/app/(main)/my-voyage/[teamId]/directory/components/EditHours.tsx @@ -6,7 +6,7 @@ import { PencilSquareIcon } from "@heroicons/react/24/outline"; import { type SetStateAction, useEffect } from "react"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import TextInput from "@/components/inputs/TextInput"; +import { TextInput } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { useAppDispatch } from "@/store/hooks"; import { editHours } from "@/app/(main)/my-voyage/[teamId]/directory/directoryService"; diff --git a/src/app/(main)/my-voyage/[teamId]/features/components/AddFeaturesInput.tsx b/src/app/(main)/my-voyage/[teamId]/features/components/AddFeaturesInput.tsx index a7252f54d..c14f6c92f 100644 --- a/src/app/(main)/my-voyage/[teamId]/features/components/AddFeaturesInput.tsx +++ b/src/app/(main)/my-voyage/[teamId]/features/components/AddFeaturesInput.tsx @@ -6,7 +6,7 @@ import { type Dispatch, type SetStateAction, useEffect } from "react"; import { useParams } from "next/navigation"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import TextInput from "@/components/inputs/TextInput"; +import { TextInput } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { useAppDispatch } from "@/store/hooks"; import useServerAction from "@/hooks/useServerAction"; diff --git a/src/app/(main)/my-voyage/[teamId]/features/components/ListItem.tsx b/src/app/(main)/my-voyage/[teamId]/features/components/ListItem.tsx index 8703128dd..f4e37ed14 100644 --- a/src/app/(main)/my-voyage/[teamId]/features/components/ListItem.tsx +++ b/src/app/(main)/my-voyage/[teamId]/features/components/ListItem.tsx @@ -3,8 +3,8 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { type SubmitHandler, useForm } from "react-hook-form"; import { useEffect, useRef, useState } from "react"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import Card from "./Card"; -import TextInput from "@/components/inputs/TextInput"; import { validateTextInput } from "@/utils/form/validateInput"; import { type Features } from "@/store/features/features/featuresSlice"; import useServerAction from "@/hooks/useServerAction"; diff --git a/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx b/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx index 182601854..d00fa2a2f 100644 --- a/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx @@ -8,7 +8,7 @@ import { TrashIcon } from "@heroicons/react/20/solid"; import { useState, useEffect } from "react"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import TextInput from "@/components/inputs/TextInput"; +import { TextInput } from "@chingu-x/components/inputs"; import Textarea from "@/components/inputs/Textarea"; import { validateTextInput } from "@/utils/form/validateInput"; import { useAppDispatch, useIdeation } from "@/store/hooks"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx index dcf096cdf..abaf66437 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx @@ -9,7 +9,7 @@ import { TrashIcon } from "@heroicons/react/20/solid"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import TextInput from "@/components/inputs/TextInput"; +import { TextInput } from "@chingu-x/components/inputs"; import Textarea from "@/components/inputs/Textarea"; import { validateTextInput } from "@/utils/form/validateInput"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx index 4f81d2761..6924689b3 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx @@ -11,8 +11,8 @@ import { LinkIcon } from "@heroicons/react/24/outline"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import DateTimePicker from "@/components/inputs/DateTimePicker"; -import TextInput from "@/components/inputs/TextInput"; import Textarea from "@/components/inputs/Textarea"; import { diff --git a/src/app/(main)/my-voyage/[teamId]/tech-stack/components/TechStackCard.tsx b/src/app/(main)/my-voyage/[teamId]/tech-stack/components/TechStackCard.tsx index f060c11dd..5315fda0d 100644 --- a/src/app/(main)/my-voyage/[teamId]/tech-stack/components/TechStackCard.tsx +++ b/src/app/(main)/my-voyage/[teamId]/tech-stack/components/TechStackCard.tsx @@ -11,6 +11,7 @@ import { AvatarGroup } from "@chingu-x/components/avatar-group"; import { Tooltip } from "@chingu-x/components/tooltip"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import GetIcon from "./GetIcons"; import AddVoteBtn from "./AddVoteBtn"; import RemoveVoteBtn from "./RemoveVoteBtn"; @@ -20,7 +21,6 @@ import { editTechItem, } from "@/myVoyage/tech-stack/techStackService"; import getTechCategory from "@/myVoyage/tech-stack/components/getTechCategory"; -import TextInput from "@/components/inputs/TextInput"; import type { TechStackItem } from "@/store/features/techStack/techStackSlice"; import { useUser, useAppDispatch, useAppSelector } from "@/store/hooks"; import useServerAction from "@/hooks/useServerAction"; diff --git a/src/app/(main)/my-voyage/[teamId]/voyage-resources/components/ResourceInput.tsx b/src/app/(main)/my-voyage/[teamId]/voyage-resources/components/ResourceInput.tsx index 7c34a192a..ab33795de 100644 --- a/src/app/(main)/my-voyage/[teamId]/voyage-resources/components/ResourceInput.tsx +++ b/src/app/(main)/my-voyage/[teamId]/voyage-resources/components/ResourceInput.tsx @@ -5,9 +5,9 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { LinkIcon } from "@heroicons/react/24/outline"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; +import { TextInput } from "@chingu-x/components/inputs"; import { useAppDispatch } from "@/store/hooks"; import { validateTextInput } from "@/utils/form/validateInput"; -import TextInput from "@/components/inputs/TextInput"; import { onOpenModal } from "@/store/features/modal/modalSlice"; import { addResource } from "@/app/(main)/my-voyage/[teamId]/voyage-resources/resourcesService"; import useServerAction from "@/hooks/useServerAction"; diff --git a/src/components/form/FormInput.tsx b/src/components/form/FormInput.tsx index 32c5ff82b..cf22b667c 100644 --- a/src/components/form/FormInput.tsx +++ b/src/components/form/FormInput.tsx @@ -3,6 +3,7 @@ import { type FieldErrors, type UseFormRegister } from "react-hook-form"; import { LinkIcon } from "@heroicons/react/24/outline"; +import { TextInput } from "@chingu-x/components/inputs"; import { LabelContent } from "./LabelContent"; import FormInputContainer from "@/components/form/FormInputContainer"; @@ -12,7 +13,6 @@ import RadioGroupVertical from "@/components/inputs/RadioGroup/RadioGroupVertica import CheckboxGroupVertical from "@/components/inputs/CheckBoxGroup/CheckboxGroupVertical"; import RadioGroupHorizontal from "@/components/inputs/RadioGroup/RadioGroupHorizontal"; import RadioGroupRating from "@/components/inputs/RadioGroup/RadioGroupRating"; -import TextInput from "@/components/inputs/TextInput"; import { getOptions, getTextInCurlyBrackets } from "@/utils/form/helpers"; import { type Question, type TeamMemberForCheckbox } from "@/utils/form/types"; diff --git a/src/components/inputs/TextInput.tsx b/src/components/inputs/TextInput.tsx deleted file mode 100644 index 3e9d41ef9..000000000 --- a/src/components/inputs/TextInput.tsx +++ /dev/null @@ -1,178 +0,0 @@ -"use client"; - -import React, { type ChangeEvent, useState } from "react"; -import { XMarkIcon } from "@heroicons/react/24/outline"; -import { EyeSlashIcon, EyeIcon } from "@heroicons/react/24/solid"; - -import { Button } from "@chingu-x/components/button"; -import { IconButton } from "@chingu-x/components/icon-button"; -import Label from "./Label"; -import FieldMessage from "./FieldMessage"; - -import { cn } from "@/lib/utils"; - -interface TextInputProps extends React.InputHTMLAttributes { - id: string; - label?: string; - placeholder: string; - defaultValue?: string; - suggestion?: string; - maxLength?: number; - errorMessage?: string | undefined; - inputGroupContent?: JSX.Element; - submitButtonText?: string | React.ReactNode; - buttonDisabled?: boolean; - ariaLabel?: string; - clearInputAction?: () => void; -} - -const TextInput = React.forwardRef( - ( - { - id, - label, - placeholder, - defaultValue, - suggestion, - maxLength, - errorMessage, - inputGroupContent, - submitButtonText, - buttonDisabled, - clearInputAction, - className, - type = "text", - ariaLabel, - ...props - }, - ref, - ) => { - const [isClearButtonVisible, setIsClearButtonVisible] = useState(false); - const [currentSuggestion, setCurrentSuggestion] = useState(suggestion); - const [showPassword, setShowPassword] = useState(false); - - function toggleShowPassword() { - setShowPassword(!showPassword); - } - - function handleOnChange(e: ChangeEvent) { - // Max length suggestion message - if (maxLength && e.target.type !== "password") { - const currentLength = e.target.value.length; - if (currentLength > 0) { - setCurrentSuggestion( - `Character length ${currentLength}/${maxLength}`, - ); - } else { - setCurrentSuggestion(suggestion); - } - } - - // Clear button toggle - if (clearInputAction && e.target.value.length > 0) { - setIsClearButtonVisible(true); - } else { - setIsClearButtonVisible(false); - } - } - - function clearInput() { - if (clearInputAction) { - clearInputAction(); - setIsClearButtonVisible(false); - } - } - - return ( -
- {/* LABEL */} - {label && } - {/* INPUT */} -
- { - // call onChange which can be passed as prop - if (props.onChange) void props.onChange(e); - // call your handler - handleOnChange(e); - }} - /> - {/* FIXED INPUT GROUP */} - {inputGroupContent && ( -
- {inputGroupContent} -
- )} - {/* SUBMIT BUTTON */} - {submitButtonText && ( - - )} - {/* CLEAR INPUT BUTTON */} - {isClearButtonVisible && ( - - - - )} - {/* SHOW/HIDE PASSWORD TOGGLE */} - {type === "password" && ( -
- {showPassword ? ( - - ) : ( - - )} -
- )} -
- -
- ); - }, -); - -TextInput.displayName = "TextInput"; - -export default TextInput; diff --git a/src/stories/components/inputs/TextInput.stories.tsx b/src/stories/components/inputs/TextInput.stories.tsx deleted file mode 100644 index 9118652e7..000000000 --- a/src/stories/components/inputs/TextInput.stories.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; - -import { FormEvent, useState } from "react"; -import { EnvelopeIcon, PlusCircleIcon } from "@heroicons/react/24/outline"; -import TextInput from "@/components/inputs/TextInput"; - -const meta = { - title: "Components/Inputs/Text Input", - component: TextInput, - parameters: { - layout: "centered", - }, - tags: ["autodocs"], - argTypes: { - id: { - description: "The input id.", - control: "text", - }, - label: { - description: "The input label (optional).", - control: "text", - }, - placeholder: { - description: "The input placeholder.", - control: "text", - }, - suggestion: { - description: "Add a short suggestion (optional).", - control: "text", - }, - maxLength: { - description: "Add maximum length (optional).", - }, - errorMessage: { - description: "Error message (optional).", - }, - inputGroupContent: { - description: "Provide an icon or a text for an input group (optional).", - control: { type: "boolean" }, - mapping: { false: undefined, true: }, - }, - submitButtonText: { - description: "A submit button text. (optional)", - }, - clearInputAction: { - description: - "An action to clear an input. If case of react-hook-form, you can pass `{() => reset({ inputId: '' })}` (optional).", - }, - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -const BaseTemplate: Story = { - decorators: [ - (Story) => ( -
- -
- ), - ], - args: { - id: "textInput", - placeholder: "Placeholder", - }, - render: ({ ...args }) => , -}; - -export const Default = { - ...BaseTemplate, -}; - -export const WithLabel = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - label: "label", - }, -}; - -export const WithSuggestion = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - suggestion: "Tip: keep it short and sweet", - }, -}; - -export const WithMaxLength = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - maxLength: 10, - }, -}; - -export const WithErrorMessage = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - errorMessage: "Required", - }, -}; - -export const InputGroup = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - inputGroupContent: , - }, -}; - -export const InputWithSaveButton: Story = { - decorators: [ - (Story) => ( -
- -
- ), - ], - args: { - id: "textInput", - placeholder: "Placeholder", - submitButtonText: "Save", - clearInputAction: () => {}, - }, - render: function Render(args) { - const [value, setValue] = useState(""); - const onSubmit = (e: FormEvent) => { - e.preventDefault(); - }; - const clearInput = () => { - setValue(""); - }; - return ( -
- setValue(e.target.value)} - clearInputAction={() => clearInput()} - /> - - ); - }, -}; - -export const InputGroupWithSaveButton: Story = { - decorators: [ - (Story) => ( -
- -
- ), - ], - args: { - id: "textInput", - placeholder: "Placeholder", - inputGroupContent: , - submitButtonText: "Save", - clearInputAction: () => {}, - }, - render: function Render(args) { - const [value, setValue] = useState(""); - const onSubmit = (e: FormEvent) => { - e.preventDefault(); - }; - const clearInput = () => { - setValue(""); - }; - return ( -
- } - submitButtonText="Save" - value={value} - onChange={(e) => setValue(e.target.value)} - clearInputAction={() => clearInput()} - /> - - ); - }, -}; From 9f919a0e30f2d9167d2ce0bc022e64adf14bc09d Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Tue, 18 Feb 2025 11:46:18 -0500 Subject: [PATCH 04/10] chore: replaced datetimepicker --- .../sprints/components/forms/MeetingForm.tsx | 3 +- src/components/inputs/DateTimePicker.tsx | 69 --------------- .../inputs/DateTimePicker.stories.tsx | 83 ------------------- 3 files changed, 1 insertion(+), 154 deletions(-) delete mode 100644 src/components/inputs/DateTimePicker.tsx delete mode 100644 src/stories/components/inputs/DateTimePicker.stories.tsx diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx index 6924689b3..1e9372c4f 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx @@ -11,8 +11,7 @@ import { LinkIcon } from "@heroicons/react/24/outline"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import { TextInput } from "@chingu-x/components/inputs"; -import DateTimePicker from "@/components/inputs/DateTimePicker"; +import { DateTimePicker, TextInput } from "@chingu-x/components/inputs"; import Textarea from "@/components/inputs/Textarea"; import { diff --git a/src/components/inputs/DateTimePicker.tsx b/src/components/inputs/DateTimePicker.tsx deleted file mode 100644 index 3f408f3c5..000000000 --- a/src/components/inputs/DateTimePicker.tsx +++ /dev/null @@ -1,69 +0,0 @@ -"use client"; - -import React from "react"; -import DatePicker, { type ReactDatePickerProps } from "react-datepicker"; -import { CalendarDaysIcon } from "@heroicons/react/24/outline"; - -import "react-datepicker/dist/react-datepicker.css"; - -import TextInput from "./TextInput"; - -export interface DatePickerInputProps extends ReactDatePickerProps { - id: string; - label: string; - selectedValue: Date; - placeholder: string; - errorMessage?: string | undefined; -} - -const DateTimePicker = React.forwardRef( - ( - { - id, - label, - selectedValue, - placeholder, - errorMessage, - className, - ...props - }, - ref, - ) => { - const filterPassedTime = (time: Date) => { - const currentDate = new Date(); - const selectedDate = new Date(time); - return currentDate.getTime() < selectedDate.getTime(); - }; - return ( -
- } - errorMessage={errorMessage} - className={className} - /> - } - ref={ref} - {...props} - /> -
- ); - }, -); - -DateTimePicker.displayName = "DateTimePicker"; - -export default DateTimePicker; diff --git a/src/stories/components/inputs/DateTimePicker.stories.tsx b/src/stories/components/inputs/DateTimePicker.stories.tsx deleted file mode 100644 index 34c323afb..000000000 --- a/src/stories/components/inputs/DateTimePicker.stories.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { useState } from "react"; - -import DateTimePicker from "@/components/inputs/DateTimePicker"; - -const meta = { - title: "Components/Inputs/DateTime Picker", - component: DateTimePicker, - parameters: { - layout: "centered", - }, - decorators: [ - (Story) => ( -
- -
- ), - ], - tags: ["autodocs"], - argTypes: { - id: { - description: "The input id.", - control: "text", - }, - label: { - description: "The input label.", - control: "text", - }, - selectedValue: { description: "Selected value.", control: "date" }, - placeholder: { - description: "The input placeholder.", - control: "text", - }, - errorMessage: { - description: "Error message (optional).", - control: "text", - }, - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -const BaseTemplate: Story = { - args: { - id: "textInput", - label: "label", - selectedValue: new Date(), - placeholder: "Placeholder", - }, - render: function Render(args) { - const [selectedValue, setSelectedValue] = useState(new Date()); - return ( - setSelectedValue(date)} - /> - ); - }, -}; - -export const Default = { - ...BaseTemplate, -}; - -export const WithErrorMessage = { - ...BaseTemplate, - args: { - ...BaseTemplate.args, - errorMessage: "Required", - }, -}; From 905d129e0af3e0482c87d85d41ce4d0564f4bbc4 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Tue, 18 Feb 2025 11:49:46 -0500 Subject: [PATCH 05/10] chore: replaced textarea --- .../ideation/components/IdeationForm.tsx | 3 +- .../components/forms/AgendaTopicForm.tsx | 3 +- .../sprints/components/forms/MeetingForm.tsx | 4 +- .../sprints/components/sections/Notes.tsx | 2 +- .../sprints/components/sections/Planning.tsx | 2 +- .../sprints/components/sections/Review.tsx | 2 +- src/components/form/FormInput.tsx | 3 +- src/components/inputs/Textarea.tsx | 120 ------------------ .../components/inputs/Textarea.stories.tsx | 88 ------------- 9 files changed, 8 insertions(+), 219 deletions(-) delete mode 100644 src/components/inputs/Textarea.tsx delete mode 100644 src/stories/components/inputs/Textarea.stories.tsx diff --git a/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx b/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx index d00fa2a2f..b7c5339bf 100644 --- a/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/ideation/components/IdeationForm.tsx @@ -8,8 +8,7 @@ import { TrashIcon } from "@heroicons/react/20/solid"; import { useState, useEffect } from "react"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import { TextInput } from "@chingu-x/components/inputs"; -import Textarea from "@/components/inputs/Textarea"; +import { TextInput, Textarea } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { useAppDispatch, useIdeation } from "@/store/hooks"; import { type IdeationData } from "@/store/features/ideation/ideationSlice"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx index abaf66437..2c2334be2 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/AgendaTopicForm.tsx @@ -9,8 +9,7 @@ import { TrashIcon } from "@heroicons/react/20/solid"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import { TextInput } from "@chingu-x/components/inputs"; -import Textarea from "@/components/inputs/Textarea"; +import { TextInput, Textarea } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { useSprint, useAppDispatch } from "@/store/hooks"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx index 1e9372c4f..08a36093b 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/forms/MeetingForm.tsx @@ -11,8 +11,8 @@ import { LinkIcon } from "@heroicons/react/24/outline"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import { DateTimePicker, TextInput } from "@chingu-x/components/inputs"; -import Textarea from "@/components/inputs/Textarea"; +import { DateTimePicker, TextInput, Textarea } from "@chingu-x/components/inputs"; + import { validateDateTimeInput, diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Notes.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Notes.tsx index 7317c3337..6e7ff504b 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Notes.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Notes.tsx @@ -8,7 +8,7 @@ import { useParams } from "next/navigation"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import Textarea from "@/components/inputs/Textarea"; +import { Textarea } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import useServerAction from "@/hooks/useServerAction"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Planning.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Planning.tsx index 4dcb865df..9c16e97b6 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Planning.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Planning.tsx @@ -8,7 +8,7 @@ import { useParams } from "next/navigation"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import Textarea from "@/components/inputs/Textarea"; +import { Textarea } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { type Section } from "@/store/features/sprint/sprintSlice"; diff --git a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Review.tsx b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Review.tsx index 6f7270297..d9b7cd7eb 100644 --- a/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Review.tsx +++ b/src/app/(main)/my-voyage/[teamId]/sprints/components/sections/Review.tsx @@ -8,7 +8,7 @@ import { useParams } from "next/navigation"; import { Button } from "@chingu-x/components/button"; import { Spinner } from "@chingu-x/components/spinner"; -import Textarea from "@/components/inputs/Textarea"; +import { Textarea } from "@chingu-x/components/inputs"; import { validateTextInput } from "@/utils/form/validateInput"; import { type Section } from "@/store/features/sprint/sprintSlice"; diff --git a/src/components/form/FormInput.tsx b/src/components/form/FormInput.tsx index cf22b667c..533b9acfb 100644 --- a/src/components/form/FormInput.tsx +++ b/src/components/form/FormInput.tsx @@ -3,12 +3,11 @@ import { type FieldErrors, type UseFormRegister } from "react-hook-form"; import { LinkIcon } from "@heroicons/react/24/outline"; -import { TextInput } from "@chingu-x/components/inputs"; +import { TextInput, Textarea } from "@chingu-x/components/inputs"; import { LabelContent } from "./LabelContent"; import FormInputContainer from "@/components/form/FormInputContainer"; import Label from "@/components/inputs/Label"; -import Textarea from "@/components/inputs/Textarea"; import RadioGroupVertical from "@/components/inputs/RadioGroup/RadioGroupVertical"; import CheckboxGroupVertical from "@/components/inputs/CheckBoxGroup/CheckboxGroupVertical"; import RadioGroupHorizontal from "@/components/inputs/RadioGroup/RadioGroupHorizontal"; diff --git a/src/components/inputs/Textarea.tsx b/src/components/inputs/Textarea.tsx deleted file mode 100644 index cce528424..000000000 --- a/src/components/inputs/Textarea.tsx +++ /dev/null @@ -1,120 +0,0 @@ -"use client"; - -import React, { - type ChangeEvent, - type ElementRef, - useEffect, - useRef, - useState, -} from "react"; - -import Label from "./Label"; -import FieldMessage from "./FieldMessage"; - -import { cn } from "@/lib/utils"; - -export interface TextareaProps - extends React.TextareaHTMLAttributes { - id: string; - label?: string; - placeholder: string; - defaultValue?: string; - suggestion?: string; - maxLength?: number; - errorMessage?: string | undefined; -} - -const Textarea = React.forwardRef( - ( - { - id, - label, - placeholder, - defaultValue, - suggestion, - maxLength, - errorMessage, - className, - ...props - }, - ref, - ) => { - const [currentSuggestion, setCurrentSuggestion] = useState(suggestion); - const textAreaRef = useRef | null>(null); - - // Set Textarea height to fit the content on first load - useEffect(() => { - // The 2 corresponds to the 2 1px borders (top and bottom): - if (textAreaRef !== null && textAreaRef.current !== null) { - textAreaRef.current.style.height = `${Math.max( - textAreaRef.current.scrollHeight + 4, - 0, - )}px`; - } - }, [textAreaRef?.current?.innerHTML]); - - function handleOnChange(e: ChangeEvent) { - // Make Textarea expand or shrink vertically to fit the content - // The 2 corresponds to the 2 1px borders (top and bottom): - e.target.style.height = e.target.style.minHeight = "auto"; - e.target.style.minHeight = `${Math.min( - e.target.scrollHeight + 4, - parseInt(e.target.style.maxHeight), - )}px`; - e.target.style.height = `${Math.max(e.target.scrollHeight + 4, 0)}px`; - - // Set character length counter - if (!maxLength) return; - - const currentLength = e.target.value.length; - if (currentLength > 0) { - setCurrentSuggestion(`Character length ${currentLength}/${maxLength}`); - } else { - setCurrentSuggestion(suggestion); - } - } - - return ( -
- {label && } -