mirror of
https://github.com/ToolJet/ToolJet
synced 2026-04-21 21:47:17 +00:00
Separates New Components from the branch
This commit is contained in:
parent
630a53df8f
commit
4e4ea4381b
41 changed files with 0 additions and 5242 deletions
|
|
@ -1,308 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Alert, AlertTitle, AlertDescription } from '../../components/ui/Alert/Alert';
|
||||
import { Info, AlertTriangle, AlertCircle, CheckCircle } from 'lucide-react';
|
||||
|
||||
// Storybook configuration
|
||||
export default {
|
||||
title: 'Components/Alert',
|
||||
component: Alert,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
layout: 'padded',
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'Alert component for displaying important messages to users with various types and background variants.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
type: {
|
||||
control: { type: 'select' },
|
||||
options: ['info', 'warning', 'danger'],
|
||||
description: 'The type of alert',
|
||||
},
|
||||
background: {
|
||||
control: { type: 'select' },
|
||||
options: ['none', 'grey', 'white', 'state-specific'],
|
||||
description: 'The background variant of the alert',
|
||||
},
|
||||
children: {
|
||||
control: 'text',
|
||||
description: 'The message content to display in the alert',
|
||||
},
|
||||
className: {
|
||||
control: 'text',
|
||||
description: 'Additional CSS classes to apply to the alert container',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Template for stories
|
||||
const Template = (args) => <Alert {...args} />;
|
||||
|
||||
// Default alert
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
children: (
|
||||
<>
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Default Alert</AlertTitle>
|
||||
<AlertDescription>This is a default alert message.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
// Alert variants with different types
|
||||
export const InfoAlert = Template.bind({});
|
||||
InfoAlert.args = {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
children: (
|
||||
<>
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Information</AlertTitle>
|
||||
<AlertDescription>This is an informational alert message.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
export const Warning = Template.bind({});
|
||||
Warning.args = {
|
||||
type: 'warning',
|
||||
background: 'none',
|
||||
children: (
|
||||
<>
|
||||
<AlertTriangle className="tw-w-4 tw-h-4 tw-text-icon-warning" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Warning</AlertTitle>
|
||||
<AlertDescription>This is a warning alert message.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
export const Danger = Template.bind({});
|
||||
Danger.args = {
|
||||
type: 'danger',
|
||||
background: 'none',
|
||||
children: (
|
||||
<>
|
||||
<AlertCircle className="tw-w-4 tw-h-4 tw-text-icon-danger" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>This is an error alert message.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
// Background variants
|
||||
export const GreyBackground = Template.bind({});
|
||||
GreyBackground.args = {
|
||||
type: 'info',
|
||||
background: 'grey',
|
||||
children: (
|
||||
<>
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Grey Background</AlertTitle>
|
||||
<AlertDescription>This alert has a grey background.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
export const WhiteBackground = Template.bind({});
|
||||
WhiteBackground.args = {
|
||||
type: 'info',
|
||||
background: 'white',
|
||||
children: (
|
||||
<>
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>White Background</AlertTitle>
|
||||
<AlertDescription>This alert has a white background with shadow.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
export const StateSpecificBackground = Template.bind({});
|
||||
StateSpecificBackground.args = {
|
||||
type: 'info',
|
||||
background: 'state-specific',
|
||||
children: (
|
||||
<>
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>State Specific Background</AlertTitle>
|
||||
<AlertDescription>This alert has a state-specific colored background.</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
// Long message variant
|
||||
export const LongMessage = Template.bind({});
|
||||
LongMessage.args = {
|
||||
type: 'warning',
|
||||
background: 'white',
|
||||
children: (
|
||||
<>
|
||||
<AlertTriangle className="tw-w-4 tw-h-4 tw-text-icon-warning" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Long Message Alert</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is a very long alert message that demonstrates how the alert component handles text wrapping and
|
||||
overflow. The message should wrap properly and maintain good readability even with extended content that spans
|
||||
multiple lines.
|
||||
</AlertDescription>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
// No icon variant
|
||||
export const NoIcon = Template.bind({});
|
||||
NoIcon.args = {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
children: (
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>No Icon Alert</AlertTitle>
|
||||
<AlertDescription>This alert has no icon.</AlertDescription>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
// All variants showcase
|
||||
export const AllVariants = () => {
|
||||
const types = ['info', 'warning', 'danger'];
|
||||
const backgrounds = ['none', 'grey', 'white', 'state-specific'];
|
||||
const icons = {
|
||||
info: Info,
|
||||
warning: AlertTriangle,
|
||||
danger: AlertCircle,
|
||||
};
|
||||
const titles = {
|
||||
info: 'Information',
|
||||
warning: 'Warning',
|
||||
danger: 'Error',
|
||||
};
|
||||
const descriptions = {
|
||||
info: 'This is an informational message.',
|
||||
warning: 'Please review your settings before proceeding.',
|
||||
danger: 'Something went wrong. Please try again.',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tw-space-y-8">
|
||||
<div>
|
||||
<h2 className="tw-text-2xl tw-font-bold tw-mb-4">Alert Component - All Variants</h2>
|
||||
<p className="tw-text-gray-600 tw-mb-6">Showcasing all 12 variants (3 types × 4 backgrounds)</p>
|
||||
</div>
|
||||
|
||||
{types.map((type) => (
|
||||
<div key={type} className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold tw-capitalize tw-text-gray-800">{type} Type</h3>
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4">
|
||||
{backgrounds.map((background) => {
|
||||
const Icon = icons[type];
|
||||
return (
|
||||
<div key={`${type}-${background}`} className="tw-space-y-2">
|
||||
<div className="tw-text-sm tw-font-medium tw-text-gray-600 tw-capitalize">
|
||||
{background.replace('-', ' ')} Background
|
||||
</div>
|
||||
<Alert type={type} background={background}>
|
||||
<Icon className="tw-w-4 tw-h-4" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>{titles[type]}</AlertTitle>
|
||||
<AlertDescription>{descriptions[type]}</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Background variants showcase
|
||||
export const BackgroundVariants = () => (
|
||||
<div className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold tw-mb-4">Background Variants</h3>
|
||||
|
||||
<Alert type="info" background="none">
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>No Background</AlertTitle>
|
||||
<AlertDescription>Alert with no background</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<Alert type="info" background="grey">
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Grey Background</AlertTitle>
|
||||
<AlertDescription>Alert with grey background</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<Alert type="info" background="white">
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>White Background</AlertTitle>
|
||||
<AlertDescription>Alert with white background and shadow</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<Alert type="info" background="state-specific">
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>State Specific Background</AlertTitle>
|
||||
<AlertDescription>Alert with state-specific colored background</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Type variants showcase
|
||||
export const TypeVariants = () => (
|
||||
<div className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold tw-mb-4">Type Variants</h3>
|
||||
|
||||
<Alert type="info" background="state-specific">
|
||||
<Info className="tw-w-4 tw-h-4 tw-text-icon-brand" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Information</AlertTitle>
|
||||
<AlertDescription>This is an informational alert with blue accent</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<Alert type="warning" background="state-specific">
|
||||
<AlertTriangle className="tw-w-4 tw-h-4 tw-text-icon-warning" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Warning</AlertTitle>
|
||||
<AlertDescription>This is a warning alert with orange accent</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<Alert type="danger" background="state-specific">
|
||||
<AlertCircle className="tw-w-4 tw-h-4 tw-text-icon-danger" />
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>This is an error alert with red accent</AlertDescription>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import React from "react";
|
||||
|
||||
export const AuthCenteredLayout = ({ children }) => {
|
||||
return (
|
||||
<div className="tw-flex tw-min-h-svh tw-w-full tw-items-center tw-justify-center tw-p-6 md:tw-p-10">
|
||||
<div className="tw-w-full tw-max-w-sm">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import React from 'react';
|
||||
import FeatureList from './FeatureList';
|
||||
|
||||
export const AuthLayout = ({ children }) => {
|
||||
return (
|
||||
<div className="tw-grid tw-min-h-svh lg:tw-grid-cols-[38%_1fr] tw-bg-background-surface-layer-01">
|
||||
<div className="tw-flex tw-flex-col tw-gap-4 tw-p-6 md:tw-p-10">
|
||||
<div className="tw-flex tw-flex-1 tw-items-center tw-justify-center">
|
||||
<div className="tw-w-full tw-max-w-xs">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tw-bg-muted tw-relative tw-hidden lg:tw-block tw-h-full tw-w-full tw-p-4">
|
||||
<div className="tw-h-full tw-w-full tw-rounded-2xl tw-object-cover tw-bg-[linear-gradient(90deg,hsla(176,61%,87%,1)_0%,hsla(150,54%,86%,1)_50%,hsla(301,68%,84%,1)_100%)] tw-flex tw-items-center tw-justify-center tw-p-8">
|
||||
<FeatureList />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
import React from 'react';
|
||||
import { DynamicIcon } from 'lucide-react/dynamic';
|
||||
|
||||
const FeatureList = () => {
|
||||
const features = [
|
||||
{
|
||||
icon: 'zap',
|
||||
title: 'Build apps, fast',
|
||||
description: 'Turn ideas into production-ready business\napplications in minutes with AI and low-code.',
|
||||
className: 'tw-text-[#FBCA73]',
|
||||
},
|
||||
{
|
||||
icon: 'workflow',
|
||||
title: 'Automate business processes',
|
||||
description: 'Use workflows and AI agents to streamline\nprocesses and drive real outcomes.',
|
||||
className: 'tw-text-[#486AE1]',
|
||||
},
|
||||
{
|
||||
icon: 'puzzle',
|
||||
title: 'Connect your data',
|
||||
description: 'Integrate with 70+ data sources instantly.',
|
||||
className: 'tw-text-[#9D78E7]',
|
||||
},
|
||||
{
|
||||
icon: 'key-round',
|
||||
title: 'Secure by default',
|
||||
description: 'Enterprise-grade compliance: authentication,\nauthorization, CI/CD, audit logs, and more.',
|
||||
className: 'tw-text-[#33B480]',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="tw-flex tw-flex-col tw-gap-16 tw-items-start tw-relative tw-w-full tw-max-w-md">
|
||||
{features.map((feature) => (
|
||||
<div key={feature.icon} className="tw-flex tw-gap-5 tw-items-start tw-relative tw-shrink-0 tw-w-full">
|
||||
<div className="tw-overflow-clip tw-relative tw-shrink-0 tw-w-16 tw-h-16 tw-flex tw-items-center tw-justify-center">
|
||||
<DynamicIcon name={feature.icon} size={30} className={feature.className} />
|
||||
</div>
|
||||
<div className="tw-flex tw-flex-col tw-gap-1.5 tw-items-start tw-relative tw-shrink-0 tw-flex-1">
|
||||
<div className="tw-flex tw-flex-col tw-items-start tw-relative tw-shrink-0 tw-w-full">
|
||||
<div className="tw-flex tw-gap-3 tw-items-center tw-relative tw-shrink-0">
|
||||
<h3 className="tw-font-medium tw-leading-8 tw-not-italic tw-relative tw-shrink-0 tw-text-text-default tw-text-xl tw-tracking-[-0.4px] tw-m-0">
|
||||
{feature.title}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p className="tw-font-normal tw-leading-6 tw-not-italic tw-relative tw-shrink-0 tw-text-text-placeholder tw-text-[15px] tw-tracking-[-0.3px] tw-w-full tw-whitespace-pre-line tw-m-0">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeatureList;
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { CornerDownLeft, Info } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
import { InlineInfoCompound } from '@/components/ui/InlineInfo/InlineInfo';
|
||||
|
||||
export function ForgotPasswordForm({ className, ...props }) {
|
||||
const {
|
||||
// Header and sign up section
|
||||
headerText,
|
||||
signupText,
|
||||
signupUrl,
|
||||
signupCTA,
|
||||
showSignup,
|
||||
|
||||
// Form fields
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
|
||||
// Admin banner
|
||||
adminContactText,
|
||||
showAdminBanner,
|
||||
showSeparator,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
emailValue,
|
||||
onEmailChange,
|
||||
|
||||
// Validation and state
|
||||
emailValidation,
|
||||
emailValidationMessage,
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-0.5 tw-min-w-96">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="forgot-password-header">
|
||||
{headerText}
|
||||
</h1>
|
||||
|
||||
{showSignup && (
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0">
|
||||
<span>{signupText}</span>
|
||||
<span>
|
||||
<Link
|
||||
to={signupUrl}
|
||||
className="tw-text-text-brand tw-text-[11px] tw-font-medium tw-no-underline tw-pl-1.5 tw-pb-0.5 tw-self-center hover:tw-text-button-primary-hover"
|
||||
tabIndex="-1"
|
||||
data-cy="create-an-account-link"
|
||||
>
|
||||
{signupCTA}
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
onChange={onEmailChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={emailValidation}
|
||||
isValidatedMessages={emailValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{buttonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
|
||||
{showSeparator && (
|
||||
<div className="tw-relative tw-flex tw-items-center tw-text-center tw-text-sm">
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
<span className="tw-px-2 tw-text-text-placeholder tw-text-lg tw-font-medium">OR</span>
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showAdminBanner && (
|
||||
<InlineInfoCompound
|
||||
type="info"
|
||||
background="state-specific"
|
||||
icon={Info}
|
||||
description={adminContactText}
|
||||
data-cy="admin-contact-banner"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
ForgotPasswordForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header and sign up section
|
||||
headerText: PropTypes.string,
|
||||
signupText: PropTypes.string,
|
||||
signupUrl: PropTypes.string,
|
||||
signupCTA: PropTypes.string,
|
||||
showSignup: PropTypes.bool,
|
||||
|
||||
// Form fields
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
|
||||
// Admin banner
|
||||
adminContactText: PropTypes.string,
|
||||
showAdminBanner: PropTypes.bool,
|
||||
showSeparator: PropTypes.bool,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
emailValue: PropTypes.string,
|
||||
onEmailChange: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
emailValidation: PropTypes.func,
|
||||
emailValidationMessage: PropTypes.object,
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
ForgotPasswordForm.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header and sign up section
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
|
||||
// Form fields
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
|
||||
// Button
|
||||
buttonText: 'Send a reset link',
|
||||
|
||||
// Admin banner
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
showSeparator: true,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
emailValue: undefined,
|
||||
onEmailChange: undefined,
|
||||
|
||||
// Validation and state
|
||||
emailValidation: undefined,
|
||||
emailValidationMessage: undefined,
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function ForgotPasswordInfoScreen({ className, ...props }) {
|
||||
const {
|
||||
// Header
|
||||
headerText,
|
||||
|
||||
// Message content
|
||||
messageText,
|
||||
email,
|
||||
|
||||
// Info text
|
||||
infoText,
|
||||
showInfo,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
onBackToLogin,
|
||||
|
||||
// Separator
|
||||
showSeparator,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<div className={cn('tw-flex tw-flex-col tw-gap-6 tw-min-w-96', className)} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-0.5">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="forgot-password-info-header">
|
||||
{headerText}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="tw-flex tw-flex-col tw-gap-4">
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0" data-cy="forgot-password-message">
|
||||
{messageText}
|
||||
{email && (
|
||||
<>
|
||||
{' '}
|
||||
<span className="tw-font-medium tw-text-text-brand">{email}</span>
|
||||
</>
|
||||
)}
|
||||
.
|
||||
</p>
|
||||
|
||||
{showInfo && (
|
||||
<p className="tw-text-sm tw-text-text-placeholder tw-mb-0" data-cy="forgot-password-info">
|
||||
{infoText}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showSeparator && (
|
||||
<div className="tw-relative tw-flex tw-items-center tw-text-center tw-text-sm">
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
<span className="tw-px-2 tw-text-muted-foreground">OR</span>
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
size="default"
|
||||
variant="outline"
|
||||
className="tw-w-fit"
|
||||
onClick={onBackToLogin}
|
||||
data-cy="back-to-login-button"
|
||||
>
|
||||
<ArrowLeft width="16" height="16" />
|
||||
{buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
ForgotPasswordInfoScreen.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header
|
||||
headerText: PropTypes.string,
|
||||
|
||||
// Message content
|
||||
messageText: PropTypes.string,
|
||||
email: PropTypes.string,
|
||||
|
||||
// Info text
|
||||
infoText: PropTypes.string,
|
||||
showInfo: PropTypes.bool,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
onBackToLogin: PropTypes.func,
|
||||
|
||||
// Separator
|
||||
showSeparator: PropTypes.bool,
|
||||
};
|
||||
|
||||
ForgotPasswordInfoScreen.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header
|
||||
headerText: 'Check your mail',
|
||||
|
||||
// Message content
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: '',
|
||||
|
||||
// Info text
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
|
||||
// Button
|
||||
buttonText: 'Back to login',
|
||||
onBackToLogin: undefined,
|
||||
|
||||
// Separator
|
||||
showSeparator: true,
|
||||
};
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import Logo from '@/modules/common/resources/images/Logo';
|
||||
|
||||
export const FormWrapper = ({ children }) => {
|
||||
return (
|
||||
<div className="tw-flex tw-flex-col tw-gap-9">
|
||||
<Logo />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
|
||||
export const GitHubSigninButton = ({ onClick, icon, text, dataCy }) => {
|
||||
return (
|
||||
<Button
|
||||
onClick={onClick}
|
||||
data-cy={dataCy}
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="large"
|
||||
className="tw-justify-center"
|
||||
>
|
||||
<SolidIcon name="github" />
|
||||
<span className="sso-text" data-cy={`${dataCy}-text`}>
|
||||
{text}
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
|
||||
export const GoogleSigninButton = ({ onClick, icon, text, dataCy }) => {
|
||||
return (
|
||||
<Button
|
||||
onClick={onClick}
|
||||
data-cy={dataCy}
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="large"
|
||||
className="tw-justify-center"
|
||||
>
|
||||
<SolidIcon name="google" />
|
||||
<span className="sso-text" data-cy={`${dataCy}-text`}>
|
||||
{text}
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CornerDownLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function InviteSignupForm({ className, ...props }) {
|
||||
const {
|
||||
// Header section
|
||||
headerText,
|
||||
descriptionText,
|
||||
|
||||
// Form fields
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
emailValue,
|
||||
emailDisabled,
|
||||
|
||||
passwordLabel,
|
||||
passwordPlaceholder,
|
||||
passwordValue,
|
||||
onPasswordChange,
|
||||
passwordValidation,
|
||||
passwordValidationMessage,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
|
||||
// Validation and state
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-min-w-20">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="">
|
||||
{headerText}
|
||||
</h1>
|
||||
|
||||
{descriptionText && (
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0">{descriptionText}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
disabled={emailDisabled || disabled}
|
||||
required
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="password" size="large">
|
||||
{passwordLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={passwordPlaceholder}
|
||||
value={passwordValue}
|
||||
onChange={onPasswordChange}
|
||||
disabled={disabled}
|
||||
showEncryption={false}
|
||||
required
|
||||
validation={passwordValidation}
|
||||
isValidatedMessages={passwordValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{buttonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
InviteSignupForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header section
|
||||
headerText: PropTypes.string,
|
||||
descriptionText: PropTypes.string,
|
||||
|
||||
// Form fields
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
emailValue: PropTypes.string,
|
||||
emailDisabled: PropTypes.bool,
|
||||
|
||||
passwordLabel: PropTypes.string,
|
||||
passwordPlaceholder: PropTypes.string,
|
||||
passwordValue: PropTypes.string,
|
||||
onPasswordChange: PropTypes.func,
|
||||
passwordValidation: PropTypes.func,
|
||||
passwordValidationMessage: PropTypes.object,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
InviteSignupForm.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header section
|
||||
headerText: 'Sign up',
|
||||
descriptionText: '',
|
||||
|
||||
// Form fields
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
emailValue: '',
|
||||
emailDisabled: true,
|
||||
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
passwordValue: '',
|
||||
onPasswordChange: undefined,
|
||||
passwordValidation: undefined,
|
||||
passwordValidationMessage: undefined,
|
||||
|
||||
// Button
|
||||
buttonText: 'Create account',
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
|
||||
// Validation and state
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CornerDownLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function JoinWorkspaceForm({ className, ...props }) {
|
||||
const {
|
||||
// Header section
|
||||
headerText,
|
||||
descriptionText,
|
||||
|
||||
// Form fields
|
||||
nameLabel,
|
||||
namePlaceholder,
|
||||
nameValue,
|
||||
onNameChange,
|
||||
nameValidation,
|
||||
nameValidationMessage,
|
||||
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
emailValue,
|
||||
onEmailChange,
|
||||
emailValidation,
|
||||
emailValidationMessage,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
|
||||
// Validation and state
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-min-w-20">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="">
|
||||
{headerText}
|
||||
</h1>
|
||||
|
||||
{descriptionText && (
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0">{descriptionText}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="name" size="large">
|
||||
{nameLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={namePlaceholder}
|
||||
value={nameValue}
|
||||
onChange={onNameChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={nameValidation}
|
||||
isValidatedMessages={nameValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
onChange={onEmailChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={emailValidation}
|
||||
isValidatedMessages={emailValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{buttonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
JoinWorkspaceForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header section
|
||||
headerText: PropTypes.string,
|
||||
descriptionText: PropTypes.string,
|
||||
|
||||
// Form fields
|
||||
nameLabel: PropTypes.string,
|
||||
namePlaceholder: PropTypes.string,
|
||||
nameValue: PropTypes.string,
|
||||
onNameChange: PropTypes.func,
|
||||
nameValidation: PropTypes.func,
|
||||
nameValidationMessage: PropTypes.object,
|
||||
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
emailValue: PropTypes.string,
|
||||
onEmailChange: PropTypes.func,
|
||||
emailValidation: PropTypes.func,
|
||||
emailValidationMessage: PropTypes.object,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
JoinWorkspaceForm.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header section
|
||||
headerText: 'Join workspace',
|
||||
descriptionText: '',
|
||||
|
||||
// Form fields
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
nameValue: '',
|
||||
onNameChange: undefined,
|
||||
nameValidation: undefined,
|
||||
nameValidationMessage: undefined,
|
||||
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
emailValue: '',
|
||||
onEmailChange: undefined,
|
||||
emailValidation: undefined,
|
||||
emailValidationMessage: undefined,
|
||||
|
||||
// Button
|
||||
buttonText: 'Accept Invite',
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
|
||||
// Validation and state
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { CornerDownLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function LoginForm({ className, ...props }) {
|
||||
const {
|
||||
// Header and sign up section
|
||||
signinHeader,
|
||||
signUpText,
|
||||
signUpUrl,
|
||||
signUpCTA,
|
||||
showSignup,
|
||||
organizationName,
|
||||
|
||||
// Form fields
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
passwordLabel,
|
||||
passwordPlaceholder,
|
||||
|
||||
// Forgot password
|
||||
showForgotPassword,
|
||||
forgotPasswordUrl,
|
||||
forgotPasswordText,
|
||||
|
||||
// Button and separator
|
||||
signinButtonText,
|
||||
orText,
|
||||
showOrSeparator,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
emailValue,
|
||||
passwordValue,
|
||||
onEmailChange,
|
||||
onPasswordChange,
|
||||
|
||||
// Validation and state
|
||||
emailValidation,
|
||||
passwordValidation,
|
||||
emailValidationMessage,
|
||||
passwordValidationMessage,
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-min-w-20">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="">
|
||||
{signinHeader}
|
||||
</h1>
|
||||
|
||||
{(organizationName || showSignup) && (
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0">
|
||||
{organizationName && (
|
||||
<>
|
||||
Sign in to the workspace -{' '}
|
||||
<span className="tw-font-medium" data-cy="workspace-name">
|
||||
{organizationName}
|
||||
</span>
|
||||
.
|
||||
</>
|
||||
)}{' '}
|
||||
{showSignup && (
|
||||
<>
|
||||
<span>{signUpText}</span>
|
||||
<span>
|
||||
<Link
|
||||
to={signUpUrl}
|
||||
className="tw-text-text-brand tw-text-[11px] tw-font-medium tw-no-underline tw-pl-1.5 tw-pb-0.5 tw-self-center hover:tw-text-button-primary-hover"
|
||||
tabIndex="-1"
|
||||
data-cy="create-an-account-link"
|
||||
>
|
||||
{signUpCTA}
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
onChange={onEmailChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={emailValidation}
|
||||
isValidatedMessages={emailValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<div className="tw-flex tw-items-center tw-justify-between">
|
||||
<Label htmlFor="password" size="large">
|
||||
{passwordLabel}
|
||||
</Label>
|
||||
{showForgotPassword && (
|
||||
<Link
|
||||
to={forgotPasswordUrl}
|
||||
tabIndex="-1"
|
||||
className="tw-text-text-brand tw-text-[11px] tw-font-medium tw-no-underline tw-pl-1.5 tw-pb-0.5 tw-self-center hover:tw-text-button-primary-hover"
|
||||
data-cy="forgot-password-link"
|
||||
>
|
||||
{forgotPasswordText}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={passwordPlaceholder}
|
||||
value={passwordValue}
|
||||
onChange={onPasswordChange}
|
||||
disabled={disabled}
|
||||
showEncryption={false}
|
||||
required
|
||||
validation={passwordValidation}
|
||||
isValidatedMessages={passwordValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{signinButtonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
{showOrSeparator && (
|
||||
<div className="tw-relative tw-flex tw-items-center tw-text-center tw-text-sm">
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
<span className="tw-px-2 tw-text-muted-foreground">{orText}</span>
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
LoginForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header and sign up section
|
||||
signinHeader: PropTypes.string,
|
||||
signUpText: PropTypes.string,
|
||||
signUpUrl: PropTypes.string,
|
||||
signUpCTA: PropTypes.string,
|
||||
showSignup: PropTypes.bool,
|
||||
organizationName: PropTypes.string,
|
||||
// Form fields
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
passwordLabel: PropTypes.string,
|
||||
|
||||
// Forgot password
|
||||
showForgotPassword: PropTypes.bool,
|
||||
forgotPasswordUrl: PropTypes.string,
|
||||
forgotPasswordText: PropTypes.string,
|
||||
|
||||
// Button and separator
|
||||
signinButtonText: PropTypes.string,
|
||||
orText: PropTypes.string,
|
||||
showOrSeparator: PropTypes.bool,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
emailValue: PropTypes.string,
|
||||
passwordValue: PropTypes.string,
|
||||
onEmailChange: PropTypes.func,
|
||||
onPasswordChange: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
emailValidation: PropTypes.func,
|
||||
passwordValidation: PropTypes.func,
|
||||
emailValidationMessage: PropTypes.object,
|
||||
passwordValidationMessage: PropTypes.object,
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
LoginForm.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header and sign up section
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: '',
|
||||
// Form fields
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
|
||||
// Forgot password
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
|
||||
// Button and separator
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
emailValue: undefined,
|
||||
passwordValue: undefined,
|
||||
onEmailChange: undefined,
|
||||
onPasswordChange: undefined,
|
||||
|
||||
// Validation and state
|
||||
emailValidation: undefined,
|
||||
passwordValidation: undefined,
|
||||
emailValidationMessage: undefined,
|
||||
passwordValidationMessage: undefined,
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CornerDownLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function SetupAdminForm({ className, ...props }) {
|
||||
const {
|
||||
// Header
|
||||
headerText,
|
||||
|
||||
// Form fields
|
||||
nameLabel,
|
||||
namePlaceholder,
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
passwordLabel,
|
||||
passwordPlaceholder,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
|
||||
// Terms and privacy
|
||||
termsText,
|
||||
showTerms,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
nameValue,
|
||||
emailValue,
|
||||
passwordValue,
|
||||
onNameChange,
|
||||
onEmailChange,
|
||||
onPasswordChange,
|
||||
|
||||
// Validation and state
|
||||
nameValidation,
|
||||
emailValidation,
|
||||
passwordValidation,
|
||||
nameValidationMessage,
|
||||
emailValidationMessage,
|
||||
passwordValidationMessage,
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-0.5 tw-min-w-96">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="setup-admin-header">
|
||||
{headerText}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="name" size="large">
|
||||
{nameLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={namePlaceholder}
|
||||
value={nameValue}
|
||||
onChange={onNameChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={nameValidation}
|
||||
isValidatedMessages={nameValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
onChange={onEmailChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={emailValidation}
|
||||
isValidatedMessages={emailValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="password" size="large">
|
||||
{passwordLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={passwordPlaceholder}
|
||||
value={passwordValue}
|
||||
onChange={onPasswordChange}
|
||||
disabled={disabled}
|
||||
showEncryption={false}
|
||||
required
|
||||
validation={passwordValidation}
|
||||
isValidatedMessages={passwordValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{buttonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
|
||||
{showTerms && (
|
||||
<p className="tw-text-xs tw-text-text-placeholder tw-mb-0" data-cy="terms-and-privacy">
|
||||
{termsText}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
SetupAdminForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header
|
||||
headerText: PropTypes.string,
|
||||
|
||||
// Form fields
|
||||
nameLabel: PropTypes.string,
|
||||
namePlaceholder: PropTypes.string,
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
passwordLabel: PropTypes.string,
|
||||
passwordPlaceholder: PropTypes.string,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
|
||||
// Terms and privacy
|
||||
termsText: PropTypes.string,
|
||||
showTerms: PropTypes.bool,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
nameValue: PropTypes.string,
|
||||
emailValue: PropTypes.string,
|
||||
passwordValue: PropTypes.string,
|
||||
onNameChange: PropTypes.func,
|
||||
onEmailChange: PropTypes.func,
|
||||
onPasswordChange: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
nameValidation: PropTypes.func,
|
||||
emailValidation: PropTypes.func,
|
||||
passwordValidation: PropTypes.func,
|
||||
nameValidationMessage: PropTypes.object,
|
||||
emailValidationMessage: PropTypes.object,
|
||||
passwordValidationMessage: PropTypes.object,
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
SetupAdminForm.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header
|
||||
headerText: 'Set up your admin account',
|
||||
|
||||
// Form fields
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
|
||||
// Button
|
||||
buttonText: 'Sign up',
|
||||
|
||||
// Terms and privacy
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
nameValue: undefined,
|
||||
emailValue: undefined,
|
||||
passwordValue: undefined,
|
||||
onNameChange: undefined,
|
||||
onEmailChange: undefined,
|
||||
onPasswordChange: undefined,
|
||||
|
||||
// Validation and state
|
||||
nameValidation: undefined,
|
||||
emailValidation: undefined,
|
||||
passwordValidation: undefined,
|
||||
nameValidationMessage: undefined,
|
||||
emailValidationMessage: undefined,
|
||||
passwordValidationMessage: undefined,
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
import * as React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { CornerDownLeft } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { FormWrapper } from "@/components/Auth/FormWrapper";
|
||||
|
||||
export function InviteSignupForm({ className, ...props }) {
|
||||
const {
|
||||
// Header section
|
||||
headerText,
|
||||
descriptionText,
|
||||
|
||||
// Form fields
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
emailValue,
|
||||
emailDisabled,
|
||||
|
||||
passwordLabel,
|
||||
passwordPlaceholder,
|
||||
passwordValue,
|
||||
onPasswordChange,
|
||||
passwordValidation,
|
||||
passwordValidationMessage,
|
||||
|
||||
// Button
|
||||
buttonText,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
|
||||
// Validation and state
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form
|
||||
className={cn("tw-flex tw-flex-col tw-gap-6", className)}
|
||||
onSubmit={onSubmit}
|
||||
{...props}
|
||||
>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2">
|
||||
<h1 className="tw-text-2xl tw-font-semibold tw-text-text-default">
|
||||
{headerText}
|
||||
</h1>
|
||||
{descriptionText && (
|
||||
<p className="tw-text-sm tw-text-text-muted">{descriptionText}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
disabled={emailDisabled || disabled}
|
||||
required
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="password" size="large">
|
||||
{passwordLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={passwordPlaceholder}
|
||||
value={passwordValue}
|
||||
onChange={onPasswordChange}
|
||||
disabled={disabled}
|
||||
showEncryption={false}
|
||||
required
|
||||
validation={passwordValidation}
|
||||
isValidatedMessages={passwordValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{buttonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
InviteSignupForm.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header section
|
||||
headerText: PropTypes.string,
|
||||
descriptionText: PropTypes.string,
|
||||
|
||||
// Form fields
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
emailValue: PropTypes.string,
|
||||
emailDisabled: PropTypes.bool,
|
||||
|
||||
passwordLabel: PropTypes.string,
|
||||
passwordPlaceholder: PropTypes.string,
|
||||
passwordValue: PropTypes.string,
|
||||
onPasswordChange: PropTypes.func,
|
||||
passwordValidation: PropTypes.func,
|
||||
passwordValidationMessage: PropTypes.object,
|
||||
|
||||
// Button
|
||||
buttonText: PropTypes.string,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
InviteSignupForm.defaultProps = {
|
||||
className: "",
|
||||
|
||||
// Header section
|
||||
headerText: "Sign in",
|
||||
descriptionText: "",
|
||||
|
||||
// Form fields
|
||||
emailLabel: "Email",
|
||||
emailPlaceholder: "Enter your email",
|
||||
emailValue: "",
|
||||
emailDisabled: true,
|
||||
|
||||
passwordLabel: "Password",
|
||||
passwordPlaceholder: "Enter password",
|
||||
passwordValue: "",
|
||||
onPasswordChange: undefined,
|
||||
passwordValidation: undefined,
|
||||
passwordValidationMessage: undefined,
|
||||
|
||||
// Button
|
||||
buttonText: "Sign in",
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
|
||||
// Validation and state
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CornerDownLeft } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
import { GoogleSigninButton } from '@/components/Auth/GoogleSigninButton';
|
||||
import { GitHubSigninButton } from '@/components/Auth/GitHubSigninButton';
|
||||
|
||||
export function SignupFormWithSSO({ className, ...props }) {
|
||||
const {
|
||||
// Header and sign in section
|
||||
signupHeader,
|
||||
signinText,
|
||||
signinUrl,
|
||||
signinCTA,
|
||||
showSignin,
|
||||
organizationName,
|
||||
|
||||
// Form fields
|
||||
nameLabel,
|
||||
namePlaceholder,
|
||||
nameValue,
|
||||
onNameChange,
|
||||
nameValidation,
|
||||
nameValidationMessage,
|
||||
|
||||
emailLabel,
|
||||
emailPlaceholder,
|
||||
emailValue,
|
||||
onEmailChange,
|
||||
emailValidation,
|
||||
emailValidationMessage,
|
||||
|
||||
passwordLabel,
|
||||
passwordPlaceholder,
|
||||
passwordValue,
|
||||
onPasswordChange,
|
||||
passwordValidation,
|
||||
passwordValidationMessage,
|
||||
|
||||
// Button and separator
|
||||
signupButtonText,
|
||||
orText,
|
||||
showOrSeparator,
|
||||
|
||||
// SSO buttons
|
||||
showSSOButtons,
|
||||
googleButtonText,
|
||||
githubButtonText,
|
||||
onGoogleSignup,
|
||||
onGitHubSignup,
|
||||
|
||||
// Form functionality
|
||||
onSubmit,
|
||||
|
||||
// Validation and state
|
||||
isLoading,
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<form className={cn('tw-flex tw-flex-col tw-gap-6', className)} onSubmit={onSubmit} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-min-w-20">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="">
|
||||
{signupHeader}
|
||||
</h1>
|
||||
|
||||
{(organizationName || showSignin) && (
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0">
|
||||
{organizationName && (
|
||||
<>
|
||||
Join the workspace -{' '}
|
||||
<span className="tw-font-medium" data-cy="workspace-name">
|
||||
{organizationName}
|
||||
</span>
|
||||
.
|
||||
</>
|
||||
)}{' '}
|
||||
{showSignin && (
|
||||
<>
|
||||
<span>{signinText}</span>
|
||||
<span>
|
||||
<a
|
||||
href={signinUrl}
|
||||
className="tw-text-text-brand tw-text-[11px] tw-font-medium tw-no-underline tw-pl-1.5 tw-pb-0.5 tw-self-center hover:tw-text-button-primary-hover"
|
||||
tabIndex="-1"
|
||||
data-cy="sign-in-link"
|
||||
>
|
||||
{signinCTA}
|
||||
</a>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-4">
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="name" size="large">
|
||||
{nameLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={namePlaceholder}
|
||||
value={nameValue}
|
||||
onChange={onNameChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={nameValidation}
|
||||
isValidatedMessages={nameValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="email" size="large">
|
||||
{emailLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder={emailPlaceholder}
|
||||
value={emailValue}
|
||||
onChange={onEmailChange}
|
||||
disabled={disabled}
|
||||
required
|
||||
validation={emailValidation}
|
||||
isValidatedMessages={emailValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-gap-0.5">
|
||||
<Label htmlFor="password" size="large">
|
||||
{passwordLabel}
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={passwordPlaceholder}
|
||||
value={passwordValue}
|
||||
onChange={onPasswordChange}
|
||||
disabled={disabled}
|
||||
showEncryption={false}
|
||||
required
|
||||
validation={passwordValidation}
|
||||
isValidatedMessages={passwordValidationMessage}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="large"
|
||||
type="submit"
|
||||
className="tw-w-fit"
|
||||
disabled={disabled || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{signupButtonText}
|
||||
<CornerDownLeft width="16" height="16" />
|
||||
</Button>
|
||||
|
||||
{showOrSeparator && (
|
||||
<div className="tw-relative tw-flex tw-items-center tw-text-center tw-text-sm">
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
<span className="tw-px-2 tw-text-muted-foreground">{orText}</span>
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showSSOButtons && (
|
||||
<div className="tw-flex tw-flex-col tw-gap-3">
|
||||
<GoogleSigninButton onClick={onGoogleSignup} text={googleButtonText} dataCy="google-signup-button" />
|
||||
<GitHubSigninButton onClick={onGitHubSignup} text={githubButtonText} dataCy="github-signup-button" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
SignupFormWithSSO.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header and sign in section
|
||||
signupHeader: PropTypes.string,
|
||||
signinText: PropTypes.string,
|
||||
signinUrl: PropTypes.string,
|
||||
signinCTA: PropTypes.string,
|
||||
showSignin: PropTypes.bool,
|
||||
organizationName: PropTypes.string,
|
||||
|
||||
// Form fields
|
||||
nameLabel: PropTypes.string,
|
||||
namePlaceholder: PropTypes.string,
|
||||
nameValue: PropTypes.string,
|
||||
onNameChange: PropTypes.func,
|
||||
nameValidation: PropTypes.func,
|
||||
nameValidationMessage: PropTypes.object,
|
||||
|
||||
emailLabel: PropTypes.string,
|
||||
emailPlaceholder: PropTypes.string,
|
||||
emailValue: PropTypes.string,
|
||||
onEmailChange: PropTypes.func,
|
||||
emailValidation: PropTypes.func,
|
||||
emailValidationMessage: PropTypes.object,
|
||||
|
||||
passwordLabel: PropTypes.string,
|
||||
passwordPlaceholder: PropTypes.string,
|
||||
passwordValue: PropTypes.string,
|
||||
onPasswordChange: PropTypes.func,
|
||||
passwordValidation: PropTypes.func,
|
||||
passwordValidationMessage: PropTypes.object,
|
||||
|
||||
// Button and separator
|
||||
signupButtonText: PropTypes.string,
|
||||
orText: PropTypes.string,
|
||||
showOrSeparator: PropTypes.bool,
|
||||
|
||||
// SSO buttons
|
||||
showSSOButtons: PropTypes.bool,
|
||||
googleButtonText: PropTypes.string,
|
||||
githubButtonText: PropTypes.string,
|
||||
onGoogleSignup: PropTypes.func,
|
||||
onGitHubSignup: PropTypes.func,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: PropTypes.func,
|
||||
|
||||
// Validation and state
|
||||
isLoading: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
SignupFormWithSSO.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header and sign in section
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: '',
|
||||
|
||||
// Form fields
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
nameValue: '',
|
||||
onNameChange: undefined,
|
||||
nameValidation: undefined,
|
||||
nameValidationMessage: undefined,
|
||||
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
emailValue: '',
|
||||
onEmailChange: undefined,
|
||||
emailValidation: undefined,
|
||||
emailValidationMessage: undefined,
|
||||
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
passwordValue: '',
|
||||
onPasswordChange: undefined,
|
||||
passwordValidation: undefined,
|
||||
passwordValidationMessage: undefined,
|
||||
|
||||
// Button and separator
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
|
||||
// SSO buttons
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
onGoogleSignup: undefined,
|
||||
onGitHubSignup: undefined,
|
||||
|
||||
// Form functionality
|
||||
onSubmit: undefined,
|
||||
|
||||
// Validation and state
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ArrowLeft, Mail } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { FormWrapper } from '@/components/Auth/FormWrapper';
|
||||
|
||||
export function SignupSuccessInfo({ className, ...props }) {
|
||||
const {
|
||||
// Header
|
||||
headerText,
|
||||
|
||||
// Message content
|
||||
messageText,
|
||||
email,
|
||||
name,
|
||||
|
||||
// Info text
|
||||
infoText,
|
||||
showInfo,
|
||||
|
||||
// Resend email
|
||||
resendButtonText,
|
||||
resendCountdownText,
|
||||
showResendButton,
|
||||
resendDisabled,
|
||||
resendCountdown,
|
||||
|
||||
// Back button
|
||||
backButtonText,
|
||||
onBackToSignup,
|
||||
|
||||
// Separator
|
||||
showSeparator,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FormWrapper>
|
||||
<div className={cn('tw-flex tw-flex-col tw-gap-6 tw-min-w-96', className)} {...props}>
|
||||
<div className="tw-flex tw-flex-col tw-gap-0.5">
|
||||
<h1 className="tw-text-4xl tw-tracking-tight tw-font-medium tw-mb-0" data-cy="signup-success-header">
|
||||
{headerText}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="tw-flex tw-flex-col tw-gap-4">
|
||||
<p className="tw-text-balance tw-text-sm tw-text-text-placeholder tw-mb-0" data-cy="signup-success-message">
|
||||
{messageText}
|
||||
{email && (
|
||||
<>
|
||||
{' '}
|
||||
<span className="tw-font-medium tw-text-text-brand">{email}</span>
|
||||
</>
|
||||
)}
|
||||
.{' '}
|
||||
{name && (
|
||||
<>
|
||||
Welcome, <span className="tw-font-medium tw-text-text-brand">{name}</span>!
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
|
||||
{showInfo && (
|
||||
<p className="tw-text-sm tw-text-text-placeholder tw-mb-0" data-cy="signup-success-info">
|
||||
{infoText}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showSeparator && (
|
||||
<div className="tw-relative tw-flex tw-items-center tw-text-center tw-text-sm">
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
<span className="tw-px-2 tw-text-text-placeholder tw-text-lg tw-font-medium">OR</span>
|
||||
<div className="tw-flex-1 tw-h-px tw-bg-border-weak" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showResendButton && (
|
||||
<Button
|
||||
size="default"
|
||||
variant="outline"
|
||||
className="tw-w-fit"
|
||||
disabled={resendDisabled}
|
||||
data-cy="resend-verification-email-button"
|
||||
>
|
||||
<Mail width="16" height="16" />
|
||||
{resendDisabled && resendCountdown > 0 ? `${resendCountdownText} ${resendCountdown}s` : resendButtonText}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
size="default"
|
||||
variant="outline"
|
||||
className="tw-w-fit"
|
||||
onClick={onBackToSignup}
|
||||
data-cy="back-to-signup-button"
|
||||
>
|
||||
<ArrowLeft width="16" height="16" />
|
||||
{backButtonText}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
SignupSuccessInfo.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
||||
// Header
|
||||
headerText: PropTypes.string,
|
||||
|
||||
// Message content
|
||||
messageText: PropTypes.string,
|
||||
email: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
|
||||
// Info text
|
||||
infoText: PropTypes.string,
|
||||
showInfo: PropTypes.bool,
|
||||
|
||||
// Resend email
|
||||
resendButtonText: PropTypes.string,
|
||||
resendCountdownText: PropTypes.string,
|
||||
showResendButton: PropTypes.bool,
|
||||
resendDisabled: PropTypes.bool,
|
||||
resendCountdown: PropTypes.number,
|
||||
|
||||
// Back button
|
||||
backButtonText: PropTypes.string,
|
||||
onBackToSignup: PropTypes.func,
|
||||
|
||||
// Separator
|
||||
showSeparator: PropTypes.bool,
|
||||
};
|
||||
|
||||
SignupSuccessInfo.defaultProps = {
|
||||
className: '',
|
||||
|
||||
// Header
|
||||
headerText: 'Check your mail',
|
||||
|
||||
// Message content
|
||||
messageText: "We've sent a verification email to",
|
||||
email: '',
|
||||
name: '',
|
||||
|
||||
// Info text
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
|
||||
// Resend email
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
|
||||
// Back button
|
||||
backButtonText: 'Back to sign up',
|
||||
onBackToSignup: undefined,
|
||||
|
||||
// Separator
|
||||
showSeparator: true,
|
||||
};
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthCenteredLayout } from '../AuthCenteredLayout';
|
||||
import { LoginForm } from '../LoginForm';
|
||||
import { SignupSuccessInfo } from '../SignupSuccessInfo';
|
||||
import { ForgotPasswordInfoScreen } from '../ForgotPasswordInfoScreen';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/AuthCenteredLayout',
|
||||
component: AuthCenteredLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the centered auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Signup Success Examples
|
||||
export const WithSignupSuccess = {
|
||||
args: {
|
||||
children: (
|
||||
<SignupSuccessInfo
|
||||
headerText="Check your mail"
|
||||
messageText="We've sent a verification email to"
|
||||
email="john.doe@example.com"
|
||||
name="John"
|
||||
infoText="Did not receive an email? Check your spam folder!"
|
||||
showInfo={true}
|
||||
resendButtonText="Resend verification email"
|
||||
resendCountdownText="Resend verification email in"
|
||||
showResendButton={true}
|
||||
resendDisabled={false}
|
||||
resendCountdown={0}
|
||||
backButtonText="Back to sign up"
|
||||
showSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Forgot Password Examples
|
||||
export const WithForgotPasswordInfo = {
|
||||
args: {
|
||||
children: (
|
||||
<ForgotPasswordInfoScreen
|
||||
headerText="Check your mail"
|
||||
messageText="We've sent a password reset link to"
|
||||
email="user@example.com"
|
||||
infoText="Did not receive an email? Check your spam folder!"
|
||||
showInfo={true}
|
||||
buttonText="Back to login"
|
||||
showSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { LoginForm } from '../LoginForm';
|
||||
import { SetupAdminForm } from '../SetupAdminForm';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/AuthLayout',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithLoginFormOrganization = {
|
||||
args: {
|
||||
children: (
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName="Acme Corporation"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Responsive Examples
|
||||
export const DesktopView = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName="Acme Corporation"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export const TabletView = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'tablet',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName="Acme Corporation"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export const MobileView = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'mobile',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName="Acme Corporation"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { AuthCenteredLayout } from '../AuthCenteredLayout';
|
||||
import { ForgotPasswordForm } from '../ForgotPasswordForm';
|
||||
import { ForgotPasswordInfoScreen } from '../ForgotPasswordInfoScreen';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Flows/ForgotPassword',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Forgot Password Flow - Form
|
||||
export const ForgotPasswordFlow = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<ForgotPasswordForm
|
||||
headerText="Forgot Password"
|
||||
signupText="New to ToolJet?"
|
||||
signupUrl="#"
|
||||
signupCTA="Create an account"
|
||||
showSignup={true}
|
||||
emailLabel="Email address"
|
||||
emailPlaceholder="Enter email address"
|
||||
buttonText="Send a reset link"
|
||||
adminContactText="Contact admin to reset your password"
|
||||
showAdminBanner={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Forgot Password Flow - Info Screen
|
||||
export const ForgotPasswordInfoFlow = {
|
||||
render: (args) => (
|
||||
<AuthCenteredLayout {...args}>
|
||||
<ForgotPasswordInfoScreen
|
||||
headerText="Check your mail"
|
||||
messageText="We've sent a password reset link to"
|
||||
email="user@example.com"
|
||||
infoText="Did not receive an email? Check your spam folder!"
|
||||
showInfo={true}
|
||||
buttonText="Back to login"
|
||||
showSeparator={true}
|
||||
/>
|
||||
</AuthCenteredLayout>
|
||||
),
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
import React from 'react';
|
||||
import { ForgotPasswordForm } from '../ForgotPasswordForm';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/ForgotPasswordForm',
|
||||
component: ForgotPasswordForm,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
headerText: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the forgot password form',
|
||||
},
|
||||
signupText: {
|
||||
control: 'text',
|
||||
description: 'Text before the sign up link',
|
||||
},
|
||||
signupUrl: {
|
||||
control: 'text',
|
||||
description: 'URL for the sign up link',
|
||||
},
|
||||
signupCTA: {
|
||||
control: 'text',
|
||||
description: 'Call-to-action text for the sign up link',
|
||||
},
|
||||
showSignup: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the signup section',
|
||||
},
|
||||
emailLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the email input field',
|
||||
},
|
||||
emailPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the email input',
|
||||
},
|
||||
buttonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the submit button',
|
||||
},
|
||||
adminContactText: {
|
||||
control: 'text',
|
||||
description: 'Text for the admin contact banner',
|
||||
},
|
||||
showAdminBanner: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the admin contact banner',
|
||||
},
|
||||
emailValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for email input',
|
||||
},
|
||||
isLoading: {
|
||||
control: 'boolean',
|
||||
description: 'Loading state for the form',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disabled state for the form',
|
||||
},
|
||||
onSubmit: {
|
||||
action: 'submitted',
|
||||
description: 'Form submission handler',
|
||||
},
|
||||
onEmailChange: {
|
||||
action: 'email changed',
|
||||
description: 'Email input change handler',
|
||||
},
|
||||
emailValidation: {
|
||||
control: false,
|
||||
description: 'Email validation function',
|
||||
},
|
||||
emailValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External email validation message object',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Send a reset link',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
},
|
||||
};
|
||||
export const NoSignup = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: '',
|
||||
signupUrl: '#',
|
||||
signupCTA: '',
|
||||
showSignup: false,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Send a reset link',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoAdminBanner = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Send a reset link',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Loading = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Sending...',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
emailValue: 'user@example.com',
|
||||
isLoading: true,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Send a reset link',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValidation = {
|
||||
args: {
|
||||
headerText: 'Forgot Password',
|
||||
signupText: 'New to ToolJet?',
|
||||
signupUrl: '#',
|
||||
signupCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
emailLabel: 'Email address',
|
||||
emailPlaceholder: 'Enter email address',
|
||||
buttonText: 'Send a reset link',
|
||||
adminContactText: 'Contact admin to reset your password',
|
||||
showAdminBanner: true,
|
||||
emailValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
if (!value) {
|
||||
return { valid: false, message: 'Email is required' };
|
||||
}
|
||||
|
||||
if (!emailRegex.test(value)) {
|
||||
return { valid: false, message: 'Please enter a valid email address' };
|
||||
}
|
||||
|
||||
return { valid: true, message: 'Email looks good!' };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
import React from 'react';
|
||||
import { ForgotPasswordInfoScreen } from '../ForgotPasswordInfoScreen';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/ForgotPasswordInfoScreen',
|
||||
component: ForgotPasswordInfoScreen,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
headerText: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the info screen',
|
||||
},
|
||||
messageText: {
|
||||
control: 'text',
|
||||
description: 'Main message text',
|
||||
},
|
||||
email: {
|
||||
control: 'text',
|
||||
description: 'Email address to display in the message',
|
||||
},
|
||||
infoText: {
|
||||
control: 'text',
|
||||
description: 'Additional info text',
|
||||
},
|
||||
showInfo: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the info text',
|
||||
},
|
||||
buttonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the back to login button',
|
||||
},
|
||||
onBackToLogin: {
|
||||
action: 'back to login clicked',
|
||||
description: 'Back to login button handler',
|
||||
},
|
||||
showSeparator: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the separator',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'user@example.com',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomHeader = {
|
||||
args: {
|
||||
headerText: 'Password Reset Sent',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'user@example.com',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongEmail = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'very.long.email.address@verylongdomainname.com',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoEmail = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to your registered email address",
|
||||
email: '',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoInfo = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'user@example.com',
|
||||
infoText: '',
|
||||
showInfo: false,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoSeparator = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'user@example.com',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomMessage = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: 'A password reset link has been sent to your email address',
|
||||
email: 'user@example.com',
|
||||
infoText: 'Please check your inbox and follow the instructions to reset your password',
|
||||
showInfo: true,
|
||||
buttonText: 'Return to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Minimal = {
|
||||
args: {
|
||||
headerText: 'Email Sent',
|
||||
messageText: 'Check your email for reset instructions',
|
||||
email: '',
|
||||
infoText: '',
|
||||
showInfo: false,
|
||||
buttonText: 'Back',
|
||||
showSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomButtonText = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a password reset link to",
|
||||
email: 'user@example.com',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
buttonText: 'Return to sign in',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongMessage = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText:
|
||||
"We've sent a password reset link to your registered email address. Please check your inbox and click the link to reset your password",
|
||||
email: 'user@example.com',
|
||||
infoText:
|
||||
'Did not receive an email? Please check your spam folder or contact support if you continue to have issues',
|
||||
showInfo: true,
|
||||
buttonText: 'Back to login',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import React from 'react';
|
||||
import { GitHubSigninButton } from '../GitHubSigninButton';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/GitHubSigninButton',
|
||||
component: GitHubSigninButton,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
onClick: {
|
||||
action: 'clicked',
|
||||
description: 'Function called when the button is clicked',
|
||||
},
|
||||
text: {
|
||||
control: 'text',
|
||||
description: 'Text displayed on the button',
|
||||
},
|
||||
dataCy: {
|
||||
control: 'text',
|
||||
description: 'Data-cy attribute for testing',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Template for creating stories
|
||||
const Template = (args) => <GitHubSigninButton {...args} />;
|
||||
|
||||
// Default story
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
text: 'Continue with GitHub',
|
||||
dataCy: 'github-signin-button',
|
||||
};
|
||||
|
||||
// Custom text story
|
||||
export const CustomText = Template.bind({});
|
||||
CustomText.args = {
|
||||
text: 'Sign in with GitHub',
|
||||
dataCy: 'github-signin-custom',
|
||||
};
|
||||
|
||||
// Short text story
|
||||
export const ShortText = Template.bind({});
|
||||
ShortText.args = {
|
||||
text: 'GitHub',
|
||||
dataCy: 'github-signin-short',
|
||||
};
|
||||
|
||||
// Long text story
|
||||
export const LongText = Template.bind({});
|
||||
LongText.args = {
|
||||
text: 'Continue with your GitHub account',
|
||||
dataCy: 'github-signin-long',
|
||||
};
|
||||
|
||||
// Without data-cy story
|
||||
export const WithoutDataCy = Template.bind({});
|
||||
WithoutDataCy.args = {
|
||||
text: 'Continue with GitHub',
|
||||
};
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { GoogleSigninButton } from '../GoogleSigninButton';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/GoogleSigninButton',
|
||||
component: GoogleSigninButton,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
onClick: {
|
||||
action: 'clicked',
|
||||
description: 'Function called when the button is clicked',
|
||||
},
|
||||
text: {
|
||||
control: 'text',
|
||||
description: 'Text displayed on the button',
|
||||
},
|
||||
dataCy: {
|
||||
control: 'text',
|
||||
description: 'Data-cy attribute for testing',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Template for creating stories
|
||||
const Template = (args) => <GoogleSigninButton {...args} />;
|
||||
|
||||
// Default story
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
text: 'Continue with Google',
|
||||
dataCy: 'google-signin-button',
|
||||
};
|
||||
|
||||
// Custom text story
|
||||
export const CustomText = Template.bind({});
|
||||
CustomText.args = {
|
||||
text: 'Sign in with Google',
|
||||
dataCy: 'google-signin-custom',
|
||||
};
|
||||
|
||||
// Short text story
|
||||
export const ShortText = Template.bind({});
|
||||
ShortText.args = {
|
||||
text: 'Google',
|
||||
dataCy: 'google-signin-short',
|
||||
};
|
||||
|
||||
// Long text story
|
||||
export const LongText = Template.bind({});
|
||||
LongText.args = {
|
||||
text: 'Continue with your Google account',
|
||||
dataCy: 'google-signin-long',
|
||||
};
|
||||
|
||||
// Without data-cy story
|
||||
export const WithoutDataCy = Template.bind({});
|
||||
WithoutDataCy.args = {
|
||||
text: 'Continue with Google',
|
||||
};
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { LoginForm } from '../LoginForm';
|
||||
import { GoogleSigninButton } from '../GoogleSigninButton';
|
||||
import { GitHubSigninButton } from '../GitHubSigninButton';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Flows/Login',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Login with Organization
|
||||
export const LoginWithOrganization = {
|
||||
args: {
|
||||
children: (
|
||||
<div className="tw-flex tw-flex-col tw-gap-6 tw-w-full">
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName=""
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
emailValue=""
|
||||
passwordValue=""
|
||||
onEmailChange={() => {}}
|
||||
onPasswordChange={() => {}}
|
||||
onSubmit={() => {}}
|
||||
isLoading={false}
|
||||
disabled={false}
|
||||
/>
|
||||
|
||||
{/* SSO Buttons */}
|
||||
<div className="tw-flex tw-flex-col tw-gap-3">
|
||||
<GoogleSigninButton
|
||||
onClick={() => console.log('Google sign in clicked')}
|
||||
text="Continue with"
|
||||
dataCy="google-signin-button"
|
||||
/>
|
||||
<GitHubSigninButton
|
||||
onClick={() => console.log('GitHub sign in clicked')}
|
||||
text="Continue with"
|
||||
dataCy="github-signin-button"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
import { LoginForm } from '../LoginForm';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/LoginForm',
|
||||
component: LoginForm,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
signinHeader: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the login form',
|
||||
},
|
||||
signUpText: {
|
||||
control: 'text',
|
||||
description: 'Text before the sign up link',
|
||||
},
|
||||
signUpUrl: {
|
||||
control: 'text',
|
||||
description: 'URL for the sign up link',
|
||||
},
|
||||
signUpCTA: {
|
||||
control: 'text',
|
||||
description: 'Call-to-action text for the sign up link',
|
||||
},
|
||||
showSignup: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the signup section',
|
||||
},
|
||||
organizationName: {
|
||||
control: 'text',
|
||||
description: 'Organization name to display in the header',
|
||||
},
|
||||
emailLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the email input field',
|
||||
},
|
||||
emailPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the email input',
|
||||
},
|
||||
passwordLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the password input field',
|
||||
},
|
||||
passwordPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the password input',
|
||||
},
|
||||
showForgotPassword: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the forgot password link',
|
||||
},
|
||||
forgotPasswordUrl: {
|
||||
control: 'text',
|
||||
description: 'URL for the forgot password link',
|
||||
},
|
||||
forgotPasswordText: {
|
||||
control: 'text',
|
||||
description: 'Text for the forgot password link',
|
||||
},
|
||||
signinButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the submit button',
|
||||
},
|
||||
orText: {
|
||||
control: 'text',
|
||||
description: 'Text for the OR separator',
|
||||
},
|
||||
showOrSeparator: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the OR separator',
|
||||
},
|
||||
emailValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for email input',
|
||||
},
|
||||
passwordValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for password input',
|
||||
},
|
||||
isLoading: {
|
||||
control: 'boolean',
|
||||
description: 'Loading state for the form',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disabled state for the form',
|
||||
},
|
||||
onSubmit: {
|
||||
action: 'submitted',
|
||||
description: 'Form submission handler',
|
||||
},
|
||||
onEmailChange: {
|
||||
action: 'email changed',
|
||||
description: 'Email input change handler',
|
||||
},
|
||||
onPasswordChange: {
|
||||
action: 'password changed',
|
||||
description: 'Password input change handler',
|
||||
},
|
||||
emailValidation: {
|
||||
control: false,
|
||||
description: 'Email validation function',
|
||||
},
|
||||
passwordValidation: {
|
||||
control: false,
|
||||
description: 'Password validation function',
|
||||
},
|
||||
emailValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External email validation message object',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External password validation message object',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: '',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomHeader = {
|
||||
args: {
|
||||
signinHeader: 'Welcome Back',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: '',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'm@example.com',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithOrganization = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: 'Acme Corporation',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const OrganizationOnly = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: '',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: '',
|
||||
showSignup: false,
|
||||
organizationName: 'TechCorp Inc.',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongOrganizationName = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: 'Very Long Organization Name That Might Wrap',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const OrganizationWithSpecialChars = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: 'Acme & Co. (Ltd.)',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyOrganizationName = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
showSignup: true,
|
||||
organizationName: '',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoOrganizationNoSignup = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: '',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: '',
|
||||
showSignup: false,
|
||||
organizationName: '',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithErrors = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'm@example.com',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
emailValue: 'invalid-email',
|
||||
passwordValue: '123',
|
||||
emailValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Please enter a valid email address',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Password must be at least 8 characters',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Loading = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'm@example.com',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Signing in...',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
emailValue: 'user@example.com',
|
||||
passwordValue: 'password123',
|
||||
isLoading: true,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomSeparator = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'm@example.com',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR CONTINUE WITH',
|
||||
showOrSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoSeparator = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'm@example.com',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Minimal = {
|
||||
args: {
|
||||
signinHeader: 'Login',
|
||||
signUpText: '',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: '',
|
||||
showSignup: false,
|
||||
organizationName: '',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
showForgotPassword: false,
|
||||
signinButtonText: 'Login',
|
||||
orText: 'OR',
|
||||
showOrSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValidation = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
emailValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
if (!value) {
|
||||
return { valid: false, message: 'Email is required' };
|
||||
}
|
||||
|
||||
if (!emailRegex.test(value)) {
|
||||
return { valid: false, message: 'Please enter a valid email address' };
|
||||
}
|
||||
|
||||
return { valid: true, message: 'Email looks good!' };
|
||||
},
|
||||
passwordValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
|
||||
if (!value) {
|
||||
return { valid: false, message: 'Password is required' };
|
||||
}
|
||||
|
||||
if (value.length < 8) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Password must be at least 8 characters',
|
||||
};
|
||||
}
|
||||
|
||||
if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Password must contain uppercase, lowercase, and number',
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true, message: 'Password is strong!' };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithExternalValidation = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
emailValue: 'user@example.com',
|
||||
passwordValue: 'password123',
|
||||
emailValidationMessage: {
|
||||
valid: true,
|
||||
message: 'Email is valid and available',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
valid: true,
|
||||
message: 'Password meets all requirements',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValidationErrors = {
|
||||
args: {
|
||||
signinHeader: 'Sign in',
|
||||
signUpText: 'New to ToolJet?',
|
||||
signUpUrl: '#',
|
||||
signUpCTA: 'Create an account',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your email',
|
||||
passwordLabel: 'Password',
|
||||
showForgotPassword: true,
|
||||
forgotPasswordUrl: '/forgot-password',
|
||||
forgotPasswordText: 'Forgot?',
|
||||
signinButtonText: 'Sign in',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
emailValue: 'invalid-email',
|
||||
passwordValue: '123',
|
||||
emailValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Please enter a valid email address',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Password must be at least 8 characters',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { LoginForm } from '../LoginForm';
|
||||
import { GoogleSigninButton } from '../GoogleSigninButton';
|
||||
import { GitHubSigninButton } from '../GitHubSigninButton';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/LoginPage',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Login Page with Organization
|
||||
export const LoginPageWithOrganization = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<div className="tw-flex tw-flex-col tw-gap-6 tw-w-full">
|
||||
<LoginForm
|
||||
signinHeader="Sign in"
|
||||
signUpText="New to ToolJet?"
|
||||
signUpUrl="#"
|
||||
signUpCTA="Create an account"
|
||||
showSignup={true}
|
||||
organizationName="Acme Corporation"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Enter password"
|
||||
showForgotPassword={true}
|
||||
forgotPasswordUrl="/forgot-password"
|
||||
forgotPasswordText="Forgot?"
|
||||
signinButtonText="Sign in"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
emailValue=""
|
||||
passwordValue=""
|
||||
onEmailChange={() => {}}
|
||||
onPasswordChange={() => {}}
|
||||
onSubmit={() => {}}
|
||||
isLoading={false}
|
||||
disabled={false}
|
||||
/>
|
||||
|
||||
{/* SSO Buttons */}
|
||||
<div className="tw-flex tw-flex-col tw-gap-3">
|
||||
<GoogleSigninButton
|
||||
onClick={() => console.log('Google sign in clicked')}
|
||||
text="Continue with"
|
||||
dataCy="google-signin-button"
|
||||
/>
|
||||
<GitHubSigninButton
|
||||
onClick={() => console.log('GitHub sign in clicked')}
|
||||
text="Continue with"
|
||||
dataCy="github-signin-button"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
import React from 'react';
|
||||
import { SetupAdminForm } from '../SetupAdminForm';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/SetupAdminForm',
|
||||
component: SetupAdminForm,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
headerText: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the setup admin form',
|
||||
},
|
||||
nameLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the name input field',
|
||||
},
|
||||
namePlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the name input',
|
||||
},
|
||||
emailLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the email input field',
|
||||
},
|
||||
emailPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the email input',
|
||||
},
|
||||
passwordLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the password input field',
|
||||
},
|
||||
passwordPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the password input',
|
||||
},
|
||||
buttonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the submit button',
|
||||
},
|
||||
termsText: {
|
||||
control: 'text',
|
||||
description: 'Text for the terms and privacy notice',
|
||||
},
|
||||
showTerms: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the terms and privacy notice',
|
||||
},
|
||||
nameValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for name input',
|
||||
},
|
||||
emailValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for email input',
|
||||
},
|
||||
passwordValue: {
|
||||
control: 'text',
|
||||
description: 'Controlled value for password input',
|
||||
},
|
||||
isLoading: {
|
||||
control: 'boolean',
|
||||
description: 'Loading state for the form',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disabled state for the form',
|
||||
},
|
||||
onSubmit: {
|
||||
action: 'submitted',
|
||||
description: 'Form submission handler',
|
||||
},
|
||||
onNameChange: {
|
||||
action: 'name changed',
|
||||
description: 'Name input change handler',
|
||||
},
|
||||
onEmailChange: {
|
||||
action: 'email changed',
|
||||
description: 'Email input change handler',
|
||||
},
|
||||
onPasswordChange: {
|
||||
action: 'password changed',
|
||||
description: 'Password input change handler',
|
||||
},
|
||||
nameValidation: {
|
||||
control: false,
|
||||
description: 'Name validation function',
|
||||
},
|
||||
emailValidation: {
|
||||
control: false,
|
||||
description: 'Email validation function',
|
||||
},
|
||||
passwordValidation: {
|
||||
control: false,
|
||||
description: 'Password validation function',
|
||||
},
|
||||
nameValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External name validation message object',
|
||||
},
|
||||
emailValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External email validation message object',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
control: 'object',
|
||||
description: 'External password validation message object',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomHeader = {
|
||||
args: {
|
||||
headerText: 'Create Admin Account',
|
||||
nameLabel: 'Full Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Work Email',
|
||||
emailPlaceholder: 'Enter your work email address',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create a secure password',
|
||||
buttonText: 'Create Account',
|
||||
termsText: 'By creating an account, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValues = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
nameValue: 'John Doe',
|
||||
emailValue: 'john.doe@company.com',
|
||||
passwordValue: 'SecurePassword123!',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValidationErrors = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
nameValue: '',
|
||||
emailValue: 'invalid-email',
|
||||
passwordValue: '123',
|
||||
nameValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Name is required',
|
||||
},
|
||||
emailValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Please enter a valid email address',
|
||||
},
|
||||
passwordValidationMessage: {
|
||||
valid: false,
|
||||
message: 'Password must be at least 8 characters',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Loading = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Creating Account...',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
nameValue: 'John Doe',
|
||||
emailValue: 'john.doe@company.com',
|
||||
passwordValue: 'SecurePassword123!',
|
||||
isLoading: true,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoTerms = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: '',
|
||||
showTerms: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithValidation = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText: 'By signing up, you agree to our Terms of Service and Privacy Policy',
|
||||
showTerms: true,
|
||||
nameValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
if (!value.trim()) {
|
||||
return { valid: false, message: 'Name is required' };
|
||||
}
|
||||
if (value.length < 2) {
|
||||
return { valid: false, message: 'Name must be at least 2 characters' };
|
||||
}
|
||||
return { valid: true, message: 'Name looks good!' };
|
||||
},
|
||||
emailValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!value) {
|
||||
return { valid: false, message: 'Email is required' };
|
||||
}
|
||||
if (!emailRegex.test(value)) {
|
||||
return { valid: false, message: 'Please enter a valid email address' };
|
||||
}
|
||||
return { valid: true, message: 'Email looks good!' };
|
||||
},
|
||||
passwordValidation: (e) => {
|
||||
const value = e.target.value;
|
||||
if (!value) {
|
||||
return { valid: false, message: 'Password is required' };
|
||||
}
|
||||
if (value.length < 8) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Password must be at least 8 characters',
|
||||
};
|
||||
}
|
||||
if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Password must contain uppercase, lowercase, and number',
|
||||
};
|
||||
}
|
||||
return { valid: true, message: 'Password is strong!' };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Minimal = {
|
||||
args: {
|
||||
headerText: 'Admin Setup',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Setup',
|
||||
termsText: '',
|
||||
showTerms: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomTerms = {
|
||||
args: {
|
||||
headerText: 'Set up your admin account',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter password',
|
||||
buttonText: 'Sign up',
|
||||
termsText:
|
||||
'By creating an admin account, you acknowledge that you have read and agree to our Terms of Service, Privacy Policy, and Data Processing Agreement.',
|
||||
showTerms: true,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { AuthCenteredLayout } from '../AuthCenteredLayout';
|
||||
import { SignupFormWithSSO } from '../SignupFormWithSSO';
|
||||
import { SignupSuccessInfo } from '../SignupSuccessInfo';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Flows/Signup',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Signup Flow - Step 1: Signup Form with SSO
|
||||
export const SignupFormFlow = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<SignupFormWithSSO
|
||||
signupHeader="Sign up"
|
||||
signinText="Already have an account?"
|
||||
signinUrl="/login"
|
||||
signinCTA="Sign in"
|
||||
showSignin={true}
|
||||
organizationName=""
|
||||
nameLabel="Name"
|
||||
namePlaceholder="Enter your full name"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Create password"
|
||||
signupButtonText="Sign up"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
showSSOButtons={true}
|
||||
googleButtonText="Sign up with"
|
||||
githubButtonText="Sign up with"
|
||||
onGoogleSignup={() => console.log('Google signup clicked')}
|
||||
onGitHubSignup={() => console.log('GitHub signup clicked')}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Signup Flow - Step 1: With Organization
|
||||
export const SignupFormWithOrganizationFlow = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<SignupFormWithSSO
|
||||
signupHeader="Sign up"
|
||||
signinText="Already have an account?"
|
||||
signinUrl="/login"
|
||||
signinCTA="Sign in"
|
||||
showSignin={true}
|
||||
organizationName="Acme Corporation"
|
||||
nameLabel="Name"
|
||||
namePlaceholder="Enter your full name"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your work email"
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Create password"
|
||||
signupButtonText="Sign up"
|
||||
orText="OR"
|
||||
showOrSeparator={true}
|
||||
showSSOButtons={true}
|
||||
googleButtonText="Sign up with"
|
||||
githubButtonText="Sign up with"
|
||||
onGoogleSignup={() => console.log('Google signup clicked')}
|
||||
onGitHubSignup={() => console.log('GitHub signup clicked')}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Signup Flow - Step 2: Signup Confirmation
|
||||
export const SignupConfirmationFlow = {
|
||||
render: (args) => (
|
||||
<AuthCenteredLayout {...args}>
|
||||
<SignupSuccessInfo
|
||||
headerText="Check your mail"
|
||||
messageText="We've sent a verification email to"
|
||||
email="user@example.com"
|
||||
name="John Doe"
|
||||
infoText="Did not receive an email? Check your spam folder!"
|
||||
showInfo={true}
|
||||
resendButtonText="Resend verification email"
|
||||
resendCountdownText="Resend verification email in"
|
||||
showResendButton={true}
|
||||
resendDisabled={false}
|
||||
resendCountdown={0}
|
||||
onResendEmail={() => console.log('Resend email clicked')}
|
||||
backButtonText="Back to sign up"
|
||||
onBackToSignup={() => console.log('Back to signup clicked')}
|
||||
showSeparator={true}
|
||||
/>
|
||||
</AuthCenteredLayout>
|
||||
),
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
import React from 'react';
|
||||
import { SignupFormWithSSO } from '../SignupFormWithSSO';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/SignupFormWithSSO',
|
||||
component: SignupFormWithSSO,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
signupHeader: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the signup form',
|
||||
},
|
||||
signinText: {
|
||||
control: 'text',
|
||||
description: 'Text for the sign in link',
|
||||
},
|
||||
signinUrl: {
|
||||
control: 'text',
|
||||
description: 'URL for the sign in link',
|
||||
},
|
||||
signinCTA: {
|
||||
control: 'text',
|
||||
description: 'Call to action text for the sign in link',
|
||||
},
|
||||
showSignin: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the sign in link',
|
||||
},
|
||||
organizationName: {
|
||||
control: 'text',
|
||||
description: 'Name of the organization to display',
|
||||
},
|
||||
nameLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the name input field',
|
||||
},
|
||||
namePlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the name input field',
|
||||
},
|
||||
emailLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the email input field',
|
||||
},
|
||||
emailPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the email input field',
|
||||
},
|
||||
passwordLabel: {
|
||||
control: 'text',
|
||||
description: 'Label for the password input field',
|
||||
},
|
||||
passwordPlaceholder: {
|
||||
control: 'text',
|
||||
description: 'Placeholder text for the password input field',
|
||||
},
|
||||
signupButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the signup button',
|
||||
},
|
||||
orText: {
|
||||
control: 'text',
|
||||
description: 'Text for the OR separator',
|
||||
},
|
||||
showOrSeparator: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the OR separator',
|
||||
},
|
||||
showSSOButtons: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the SSO buttons',
|
||||
},
|
||||
googleButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the Google signup button',
|
||||
},
|
||||
githubButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the GitHub signup button',
|
||||
},
|
||||
onGoogleSignup: {
|
||||
action: 'google signup clicked',
|
||||
description: 'Google signup button handler',
|
||||
},
|
||||
onGitHubSignup: {
|
||||
action: 'github signup clicked',
|
||||
description: 'GitHub signup button handler',
|
||||
},
|
||||
onSubmit: {
|
||||
action: 'form submitted',
|
||||
description: 'Form submission handler',
|
||||
},
|
||||
isLoading: {
|
||||
control: 'boolean',
|
||||
description: 'Loading state for the form',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disabled state for the form',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: '',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithOrganization = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: 'Acme Corporation',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithoutSSO = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: '',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: false,
|
||||
showSSOButtons: false,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithoutSigninLink = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: false,
|
||||
organizationName: '',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Loading = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: '',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: true,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
signupHeader: 'Sign up',
|
||||
signinText: 'Already have an account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Sign in',
|
||||
showSignin: true,
|
||||
organizationName: '',
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Enter your full name',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Enter your work email',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Create password',
|
||||
signupButtonText: 'Sign up',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Sign up with',
|
||||
githubButtonText: 'Sign up with',
|
||||
isLoading: false,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomTexts = {
|
||||
args: {
|
||||
signupHeader: 'Create Account',
|
||||
signinText: 'Have an existing account?',
|
||||
signinUrl: '/login',
|
||||
signinCTA: 'Log in',
|
||||
showSignin: true,
|
||||
organizationName: 'TechCorp',
|
||||
nameLabel: 'Full Name',
|
||||
namePlaceholder: 'Enter your complete name',
|
||||
emailLabel: 'Work Email',
|
||||
emailPlaceholder: 'Enter your company email',
|
||||
passwordLabel: 'Secure Password',
|
||||
passwordPlaceholder: 'Create a strong password',
|
||||
signupButtonText: 'Create Account',
|
||||
orText: 'OR',
|
||||
showOrSeparator: true,
|
||||
showSSOButtons: true,
|
||||
googleButtonText: 'Continue with',
|
||||
githubButtonText: 'Continue with',
|
||||
isLoading: false,
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
import React from 'react';
|
||||
import { SignupSuccessInfo } from '../SignupSuccessInfo';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Blocks/SignupSuccessInfo',
|
||||
component: SignupSuccessInfo,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
headerText: {
|
||||
control: 'text',
|
||||
description: 'The main heading text for the signup success screen',
|
||||
},
|
||||
messageText: {
|
||||
control: 'text',
|
||||
description: 'Main message text',
|
||||
},
|
||||
email: {
|
||||
control: 'text',
|
||||
description: 'Email address to display in the message',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
description: 'User name to display in the message',
|
||||
},
|
||||
infoText: {
|
||||
control: 'text',
|
||||
description: 'Additional info text',
|
||||
},
|
||||
showInfo: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the info text',
|
||||
},
|
||||
resendButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the resend verification email button',
|
||||
},
|
||||
resendCountdownText: {
|
||||
control: 'text',
|
||||
description: 'Text for the resend countdown',
|
||||
},
|
||||
showResendButton: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the resend button',
|
||||
},
|
||||
resendDisabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disabled state for the resend button',
|
||||
},
|
||||
resendCountdown: {
|
||||
control: 'number',
|
||||
description: 'Countdown value for resend button',
|
||||
},
|
||||
backButtonText: {
|
||||
control: 'text',
|
||||
description: 'Text for the back to signup button',
|
||||
},
|
||||
onBackToSignup: {
|
||||
action: 'back to signup clicked',
|
||||
description: 'Back to signup button handler',
|
||||
},
|
||||
showSeparator: {
|
||||
control: 'boolean',
|
||||
description: 'Show or hide the separator',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomHeader = {
|
||||
args: {
|
||||
headerText: 'Account Created Successfully',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithEmailOnly = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: '',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithNameOnly = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to your registered email address",
|
||||
email: '',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongEmail = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'very.long.email.address@verylongdomainname.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoInfo = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: '',
|
||||
showInfo: false,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoResendButton = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: false,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const ResendDisabled = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: true,
|
||||
resendCountdown: 15,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoSeparator = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomMessage = {
|
||||
args: {
|
||||
headerText: 'Account Created',
|
||||
messageText: 'A verification email has been sent to your email address',
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Please check your inbox and follow the instructions to verify your account',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Return to signup',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Minimal = {
|
||||
args: {
|
||||
headerText: 'Email Sent',
|
||||
messageText: 'Check your email for verification instructions',
|
||||
email: '',
|
||||
name: '',
|
||||
infoText: '',
|
||||
showInfo: false,
|
||||
resendButtonText: 'Resend',
|
||||
resendCountdownText: 'Resend in',
|
||||
showResendButton: false,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back',
|
||||
showSeparator: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomButtonTexts = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText: "We've sent a verification email to",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText: 'Did not receive an email? Check your spam folder!',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Send another verification email',
|
||||
resendCountdownText: 'Send another email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Return to registration',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongMessage = {
|
||||
args: {
|
||||
headerText: 'Check your mail',
|
||||
messageText:
|
||||
"We've sent a verification email to your registered email address. Please check your inbox and click the link to verify your account and continue with the setup process",
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
infoText:
|
||||
'Did not receive an email? Please check your spam folder or contact support if you continue to have issues with email delivery',
|
||||
showInfo: true,
|
||||
resendButtonText: 'Resend verification email',
|
||||
resendCountdownText: 'Resend verification email in',
|
||||
showResendButton: true,
|
||||
resendDisabled: false,
|
||||
resendCountdown: 0,
|
||||
backButtonText: 'Back to sign up',
|
||||
showSeparator: true,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import React from 'react';
|
||||
import { AuthLayout } from '../AuthLayout';
|
||||
import { InviteSignupForm } from '../InviteSignupForm';
|
||||
import { JoinWorkspaceForm } from '../JoinWorkspaceForm';
|
||||
|
||||
export default {
|
||||
title: 'Auth/Flows/TeamInvite',
|
||||
component: AuthLayout,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewport: {
|
||||
viewports: {
|
||||
desktop: {
|
||||
name: 'Desktop',
|
||||
styles: {
|
||||
width: '1440px',
|
||||
height: '900px',
|
||||
},
|
||||
},
|
||||
tablet: {
|
||||
name: 'Tablet',
|
||||
styles: {
|
||||
width: '768px',
|
||||
height: '1024px',
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
name: 'Mobile',
|
||||
styles: {
|
||||
width: '375px',
|
||||
height: '667px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
children: {
|
||||
control: false,
|
||||
description: 'Content to be displayed within the auth layout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Team Invite Flow - Step 1: Invite Signup
|
||||
export const TeamInviteSignupFlow = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<InviteSignupForm
|
||||
headerText="Sign up"
|
||||
descriptionText="You have been invited to join a workspace. Please create your account to continue."
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your email"
|
||||
emailValue="nithin@dev.io"
|
||||
emailDisabled={true}
|
||||
passwordLabel="Password"
|
||||
passwordPlaceholder="Create password"
|
||||
buttonText="Create account"
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// Team Invite Flow - Step 2: Join Workspace
|
||||
export const TeamInviteJoinWorkspaceFlow = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'desktop',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: (
|
||||
<JoinWorkspaceForm
|
||||
headerText="Join Dev's workspace"
|
||||
descriptionText="You are invited to a workspace Dev's workspace. Accept the invite to join the workspace."
|
||||
nameLabel="Name"
|
||||
namePlaceholder="Enter your name"
|
||||
nameValue="Nithin"
|
||||
emailLabel="Email"
|
||||
emailPlaceholder="Enter your email"
|
||||
emailValue="nithin@dev.io"
|
||||
buttonText="Accept Invite"
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const alertVariants = cva('tw-relative tw-w-full tw-rounded-md tw-p-3 tw-text-xs tw-flex tw-gap-1.5 tw-items-start', {
|
||||
variants: {
|
||||
type: {
|
||||
info: '',
|
||||
warning: '',
|
||||
danger: '',
|
||||
},
|
||||
background: {
|
||||
none: '',
|
||||
grey: 'tw-bg-interactive-default',
|
||||
white: 'tw-bg-background-surface-layer-01 tw-shadow-elevation-100',
|
||||
'state-specific': '',
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// Info variants
|
||||
{
|
||||
type: 'info',
|
||||
background: 'state-specific',
|
||||
class: 'tw-bg-background-accent-weak',
|
||||
},
|
||||
// Warning variants
|
||||
{
|
||||
type: 'warning',
|
||||
background: 'state-specific',
|
||||
class: 'tw-bg-background-warning-weak',
|
||||
},
|
||||
// Danger variants
|
||||
{
|
||||
type: 'danger',
|
||||
background: 'state-specific',
|
||||
class: 'tw-bg-background-error-weak',
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
const Alert = React.forwardRef(({ className, type, background, ...props }, ref) => (
|
||||
<div ref={ref} role="alert" className={cn(alertVariants({ type, background }), className)} {...props} />
|
||||
));
|
||||
Alert.displayName = 'Alert';
|
||||
|
||||
const AlertTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn('tw-font-medium tw-leading-[18px] tw-text-[#2d343b] tw-text-[12px] tw-mb-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertTitle.displayName = 'AlertTitle';
|
||||
|
||||
const AlertDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn('tw-font-normal tw-leading-[18px] tw-text-text-placeholder tw-text-[12px]', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDescription.displayName = 'AlertDescription';
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription };
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { generateCypressDataCy } from '../../../modules/common/helpers/cypressHelpers.js';
|
||||
|
||||
const EncryptedField = ({ propertyKey, isEditing, handleEncryptedFieldsToggle, isDisabled, children }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="d-flex justify-content-between w-100">
|
||||
<div className="mx-1 col">
|
||||
<Button
|
||||
type="a"
|
||||
variant="tertiary"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
disabled={isDisabled}
|
||||
onClick={(e) => handleEncryptedFieldsToggle(e, propertyKey)}
|
||||
data-cy={`button-${generateCypressDataCy(isEditing ? 'Cancel' : 'Edit')}`}
|
||||
>
|
||||
{isEditing ? 'Cancel' : 'Edit'}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="col-auto mb-2">
|
||||
<small className="text-green" data-cy="encrypted-text">
|
||||
<img
|
||||
className="mx-2 encrypted-icon"
|
||||
src="assets/images/icons/padlock.svg"
|
||||
width="12"
|
||||
height="12"
|
||||
alt="Encrypted"
|
||||
/>
|
||||
Encrypted
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EncryptedField;
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Alert, AlertTitle, AlertDescription } from '../Alert/Alert';
|
||||
|
||||
// Icon color variants based on type
|
||||
const getIconColor = (type) => {
|
||||
switch (type) {
|
||||
case 'info':
|
||||
return 'tw-text-icon-brand';
|
||||
case 'warning':
|
||||
return 'tw-text-icon-warning';
|
||||
case 'danger':
|
||||
return 'tw-text-icon-danger';
|
||||
default:
|
||||
return 'tw-text-icon-brand';
|
||||
}
|
||||
};
|
||||
|
||||
// Compound component that accepts title, icon, description, and button props
|
||||
const InlineInfoCompound = React.forwardRef(
|
||||
({ className, type = 'info', background = 'none', title, icon: Icon, description, button, ...props }, ref) => (
|
||||
<Alert ref={ref} type={type} background={background} className={className} {...props}>
|
||||
{Icon && (
|
||||
<div className="tw-shrink-0 tw-w-[18px] tw-h-[18px]">
|
||||
<Icon className={cn('tw-w-full tw-h-full', getIconColor(type))} />
|
||||
</div>
|
||||
)}
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-items-start">
|
||||
{title && <AlertTitle>{title}</AlertTitle>}
|
||||
{description && <AlertDescription>{description}</AlertDescription>}
|
||||
{button && <div className="tw-mt-1">{button}</div>}
|
||||
</div>
|
||||
</Alert>
|
||||
)
|
||||
);
|
||||
InlineInfoCompound.displayName = 'InlineInfoCompound';
|
||||
|
||||
export { InlineInfoCompound };
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
import React from 'react';
|
||||
import { InlineInfoCompound } from './InlineInfo';
|
||||
import { Info, AlertTriangle, AlertCircle } from 'lucide-react';
|
||||
import { Button } from '../Button/Button';
|
||||
|
||||
export default {
|
||||
title: 'UI/InlineInfo',
|
||||
component: InlineInfoCompound,
|
||||
parameters: {
|
||||
layout: 'padded',
|
||||
},
|
||||
argTypes: {
|
||||
type: {
|
||||
control: { type: 'select' },
|
||||
options: ['info', 'warning', 'danger'],
|
||||
},
|
||||
background: {
|
||||
control: { type: 'select' },
|
||||
options: ['none', 'grey', 'white', 'state-specific'],
|
||||
},
|
||||
title: {
|
||||
control: { type: 'text' },
|
||||
},
|
||||
description: {
|
||||
control: { type: 'text' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args) => <InlineInfoCompound {...args} />;
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
title: 'Information',
|
||||
description: 'This is an informational message.',
|
||||
icon: Info,
|
||||
button: (
|
||||
<Button size="small" variant="outline">
|
||||
Learn More
|
||||
</Button>
|
||||
),
|
||||
};
|
||||
|
||||
// All Variants Grid
|
||||
export const AllVariants = () => {
|
||||
const types = ['info', 'warning', 'danger'];
|
||||
const backgrounds = ['none', 'grey', 'white', 'state-specific'];
|
||||
const icons = {
|
||||
info: Info,
|
||||
warning: AlertTriangle,
|
||||
danger: AlertCircle,
|
||||
};
|
||||
const titles = {
|
||||
info: 'Information',
|
||||
warning: 'Warning',
|
||||
danger: 'Error',
|
||||
};
|
||||
const descriptions = {
|
||||
info: 'This is an informational message.',
|
||||
warning: 'Please review your settings before proceeding.',
|
||||
danger: 'Something went wrong. Please try again.',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tw-space-y-8">
|
||||
<div>
|
||||
<h2 className="tw-text-2xl tw-font-bold tw-mb-4">InlineInfo Compound Component - All Variants</h2>
|
||||
<p className="tw-text-gray-600 tw-mb-6">
|
||||
Showcasing all 12 variants from Figma design (3 types × 4 backgrounds)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{types.map((type) => (
|
||||
<div key={type} className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold tw-capitalize tw-text-gray-800">{type} Type</h3>
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4">
|
||||
{backgrounds.map((background) => (
|
||||
<div key={`${type}-${background}`} className="tw-space-y-2">
|
||||
<div className="tw-text-sm tw-font-medium tw-text-gray-600 tw-capitalize">
|
||||
{background.replace('-', ' ')} Background
|
||||
</div>
|
||||
<InlineInfoCompound
|
||||
type={type}
|
||||
background={background}
|
||||
icon={icons[type]}
|
||||
title={titles[type]}
|
||||
description={descriptions[type]}
|
||||
button={
|
||||
<Button size="sm" variant={type === 'danger' ? 'destructive' : 'outline'}>
|
||||
Action
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Individual Type Stories
|
||||
export const InfoVariants = () => (
|
||||
<div className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold">Info Type Variants</h3>
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4">
|
||||
{['none', 'grey', 'white', 'state-specific'].map((background) => (
|
||||
<div key={background} className="tw-space-y-2">
|
||||
<div className="tw-text-sm tw-font-medium tw-text-gray-600 tw-capitalize">
|
||||
{background.replace('-', ' ')} Background
|
||||
</div>
|
||||
<InlineInfoCompound
|
||||
type="info"
|
||||
background={background}
|
||||
icon={Info}
|
||||
title="Information"
|
||||
description="This is an informational message."
|
||||
button={
|
||||
<Button size="sm" variant="outline">
|
||||
Learn More
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const WarningVariants = () => (
|
||||
<div className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold">Warning Type Variants</h3>
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4">
|
||||
{['none', 'grey', 'white', 'state-specific'].map((background) => (
|
||||
<div key={background} className="tw-space-y-2">
|
||||
<div className="tw-text-sm tw-font-medium tw-text-gray-600 tw-capitalize">
|
||||
{background.replace('-', ' ')} Background
|
||||
</div>
|
||||
<InlineInfoCompound
|
||||
type="warning"
|
||||
background={background}
|
||||
icon={AlertTriangle}
|
||||
title="Warning"
|
||||
description="Please review your settings before proceeding."
|
||||
button={
|
||||
<Button size="sm" variant="outline">
|
||||
Review
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const DangerVariants = () => (
|
||||
<div className="tw-space-y-4">
|
||||
<h3 className="tw-text-lg tw-font-semibold">Danger Type Variants</h3>
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4">
|
||||
{['none', 'grey', 'white', 'state-specific'].map((background) => (
|
||||
<div key={background} className="tw-space-y-2">
|
||||
<div className="tw-text-sm tw-font-medium tw-text-gray-600 tw-capitalize">
|
||||
{background.replace('-', ' ')} Background
|
||||
</div>
|
||||
<InlineInfoCompound
|
||||
type="danger"
|
||||
background={background}
|
||||
icon={AlertCircle}
|
||||
title="Error"
|
||||
description="Something went wrong. Please try again."
|
||||
button={
|
||||
<Button size="sm" variant="destructive">
|
||||
Retry
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Interactive Playground
|
||||
export const Playground = Template.bind({});
|
||||
Playground.args = {
|
||||
type: 'info',
|
||||
background: 'none',
|
||||
title: 'Custom Title',
|
||||
description: 'Custom description text goes here.',
|
||||
icon: Info,
|
||||
button: (
|
||||
<Button size="sm" variant="outline">
|
||||
Custom Button
|
||||
</Button>
|
||||
),
|
||||
};
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import { Button, buttonVariants } from './InlineInfo/InlineInfo';
|
||||
|
||||
export { Button, buttonVariants };
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import { Button, buttonVariants } from './Button/Button';
|
||||
|
||||
export { Button, buttonVariants };
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './Card/Index';
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import InputComponent from './Input/Index';
|
||||
import EditableTitleInput from './Input/EditableTitleInput/Index';
|
||||
|
||||
export { InputComponent as Input, EditableTitleInput };
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import { Label } from './Label/Label';
|
||||
|
||||
export { Label };
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* Custom hook for password input functionality
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {Function} options.onChange - Change handler function
|
||||
* @param {Function} options.validation - Validation function
|
||||
* @param {Object} options.isValidatedMessages - External validation messages
|
||||
* @param {boolean} options.disabled - Whether input is disabled
|
||||
* @returns {Object} Password input state and handlers
|
||||
*/
|
||||
export const usePasswordInput = ({ onChange, validation, isValidatedMessages }) => {
|
||||
const [isValid, setIsValid] = useState(null);
|
||||
const [message, setMessage] = useState('');
|
||||
|
||||
/**
|
||||
* Handle input change with validation
|
||||
* @param {Event} e - Input change event
|
||||
*/
|
||||
const handleChange = (e) => {
|
||||
if (validation) {
|
||||
const validateObj = validation(e);
|
||||
setIsValid(validateObj.valid);
|
||||
setMessage(validateObj.message);
|
||||
onChange(e, validateObj);
|
||||
} else {
|
||||
onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Update validation state when external validation messages change
|
||||
useEffect(() => {
|
||||
if (isValidatedMessages) {
|
||||
setIsValid(isValidatedMessages.valid);
|
||||
setMessage(isValidatedMessages.message);
|
||||
}
|
||||
}, [isValidatedMessages]);
|
||||
|
||||
return {
|
||||
// State
|
||||
isValid,
|
||||
message,
|
||||
|
||||
// Handlers
|
||||
handleChange,
|
||||
};
|
||||
};
|
||||
Loading…
Reference in a new issue