diff --git a/libs/shared/lib/components/inputs/emailInput.stories.tsx b/libs/shared/lib/components/inputs/emailInput.stories.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1e5425a8169e3b37fab7530f3cfb3288e5bbceeb --- /dev/null +++ b/libs/shared/lib/components/inputs/emailInput.stories.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { EmailInput } from '.'; + +const Component: Meta<typeof EmailInput> = { + title: 'Components/Inputs/EmailInput', + component: EmailInput, + argTypes: { onChange: {} }, + decorators: [(Story) => <div className="w-52 m-5">{Story()}</div>], +}; + +export default Component; +type Story = StoryObj<typeof Component>; + +export const EmailInputStory: Story = { + args: { + type: 'email', + placeholder: 'Enter your email address', + required: true, + onChange: (value) => { + console.log(value); // Handle email input changes here + }, + }, +}; diff --git a/libs/shared/lib/components/inputs/index.tsx b/libs/shared/lib/components/inputs/index.tsx index dee391156c43ed7b65d004b8e0779c6c3167a610..b61c129870e8c0e0754e09c76e4e64718fa729de 100644 --- a/libs/shared/lib/components/inputs/index.tsx +++ b/libs/shared/lib/components/inputs/index.tsx @@ -129,6 +129,25 @@ type DropdownProps = { onChange?: (value: number | string) => void; }; +type EmailProps = { + type: 'email'; + size?: 'xs' | 'sm' | 'md' | 'xl'; + placeholder?: string; + value: string; + required?: boolean; + errorText?: string; + visible?: boolean; + disabled?: boolean; + tooltip?: string; + inline?: boolean; + info?: string; + className?: string; + initialEmails?: string[]; + validate?: (value: any) => boolean; + onChange?: (value: string) => void; + onClick?: (e: React.MouseEvent<HTMLInputElement>) => void; +}; + export type InputProps = | TextProps | SliderProps @@ -138,7 +157,8 @@ export type InputProps = | BooleanProps | NumberProps | TimeProps - | ToggleSwitchProps; + | ToggleSwitchProps + | EmailProps; export const Input = (props: InputProps) => { switch (props.type) { @@ -160,6 +180,8 @@ export const Input = (props: InputProps) => { return <TimeInput {...(props as TimeProps)} />; case 'toggle': return <ToggleSwitchInput {...(props as ToggleSwitchProps)} />; + case 'email': + return <EmailInput {...(props as EmailProps)} />; default: return null; } @@ -669,3 +691,80 @@ export const ToggleSwitchInput = ({ label, classText, value, tooltip, onChange } </Tooltip> ); }; + +export const EmailInput = ({ + placeholder, + value = '', + size = 'md', + required = false, + visible = true, + errorText, + validate, + disabled = false, + onChange, + onClick = () => {}, + inline = false, + tooltip, + info, + className, + initialEmails = [], +}: EmailProps) => { + const [emails, setEmails] = useState<string[]>(initialEmails); + const [currentInput, setCurrentInput] = useState<string>(''); + + const isValidEmail = (email: string): boolean => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const addEmail = () => { + if (currentInput.trim() && isValidEmail(currentInput)) { + setEmails((prev) => [...prev, currentInput.trim()]); + setCurrentInput(''); + } + }; + + const removeEmail = (index: number) => { + setEmails((prev) => prev.filter((_, i) => i !== index)); + }; + + const handleInputChange = (value: string) => { + if (value.includes(' ')) { + addEmail(); + setCurrentInput(''); + } else { + setCurrentInput(value); + } + }; + + return ( + <div className="w-full"> + <div className="flex flex-wrap ç gap-2 cursor-pointer m-0"> + {emails.map((email, index) => ( + <div + key={index} + className="flex items-center align-items mb-2 gap-1 bg-secondary-100 border text-seccondary-700 px-3 py-1 rounded-full text-sm hover:bg-secondary-200" + > + <span>{email}</span> + <Button + variantType="secondary" + variant="ghost" + rounded + size="2xs" + iconComponent="icon-[ic--baseline-close]" + onClick={() => removeEmail(index)} + /> + </div> + ))} + </div> + + <Input + type="text" + value={currentInput} + onChange={handleInputChange} + placeholder={placeholder} + className="w-full outline-none text-sm text-gray-700" + /> + </div> + ); +}; diff --git a/libs/shared/lib/insight-sharing/FormAlert.tsx b/libs/shared/lib/insight-sharing/FormAlert.tsx index 1909f4e3145d5bf3adb8ef83810f34633cc91ca6..8e3ae247a75dff248900334c265a891d574fa0ad 100644 --- a/libs/shared/lib/insight-sharing/FormAlert.tsx +++ b/libs/shared/lib/insight-sharing/FormAlert.tsx @@ -144,20 +144,14 @@ export function FormAlert(props: Props) { <span className="font-semibold">Recipient(s)</span> </AccordionHead> <AccordionBody> - <div> + <div className="mb-4"> <Input - type="text" - value={recipientInput} + type="email" + placeholder="example@graphpolaris.com" onChange={(value) => { setRecipientInput(String(value)); - const recipientList = String(value) - .split(/[, ]/) - .map((r) => r.trim()) - .filter((r) => r.length > 0); - setRecipients(recipientList); }} - placeholder="Enter recipient(s)" - className="w-full" + value={recipientInput} /> </div> </AccordionBody>