forked from patternfly/patternfly-react
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(LoginPage): add LoginPage component with storybook and tests. (p…
…atternfly#362) * Update to current Patternfly-react version. * Fixed HTML structure in the BasicLoginPage to be exactley like the pattern, removed all custom styles. * Rebase, Add 'noop' wherever it's needed, Removed 'onInputKeyUp' for no use. * Add additionalFields prop that allow adding more elements inside the LoginCardForm, under the password field. * Refactor capslock validation to support all browsers, Update tests, Fix language dropdown classes, Refactor social-columns. * Removed the hr from social-login-page * Export all login page iner components, Removed all images and import them from patternfly instead, Rename ForgotPassword, InputWarning and RememberMe
- Loading branch information
Showing
43 changed files
with
2,991 additions
and
1 deletion.
There are no files selected for viewing
Submodule out8492
added at
30cace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
packages/patternfly-react/src/components/LoginPage/LoginPage.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import Container from './components/LoginPageComponents/LoginPageContainer'; | ||
import Header from './components/LoginPageComponents/LoginPageHeader'; | ||
import Footer from './components/LoginPageComponents/LoginPageFooter'; | ||
import FooterLinks from './components/LoginPageComponents/LoginFooterLinks'; | ||
import LoginCard from './components/LoginCardComponents/LoginCard'; | ||
import WithTranslation from './components/LoginPageComponents/LoginPageWithTranslation'; | ||
import LoginPageAlert from './components/LoginPageComponents/LoginPageAlert'; | ||
import LoginPageLink from './components/LoginPageComponents/LoginPageLink'; | ||
import SocialLoginPage from './SocialLoginPage'; | ||
import SocialLoginPageContainer from './components/LoginPageComponents/SocialLoginPageContainer'; | ||
import BasicLoginPageLayout from './components/LoginPageComponents/BasicLoginPageLayout'; | ||
|
||
const LoginPagePattern = ({ container, header, footerLinks, card }) => ( | ||
<LoginPage.Container {...container}> | ||
<LoginPage.Alert {...container.alert} /> | ||
<LoginPage.BasicLayout> | ||
<LoginPage.Header {...header} /> | ||
<LoginCard.BasicLayout> | ||
<LoginCard> | ||
<LoginCard.Header> | ||
<LoginCard.LanguagePicker | ||
selectedLanguage={card.selectedLanguage} | ||
availableLanguages={card.availableLanguages} | ||
onLanguageChange={card.onLanguageChange} | ||
/> | ||
<h1>{card.title}</h1> | ||
</LoginCard.Header> | ||
<LoginCard.WithValidation {...card.form}> | ||
<LoginCard.Form /> | ||
</LoginCard.WithValidation> | ||
<LoginCard.SignUp {...card.signUp} /> | ||
</LoginCard> | ||
<LoginPage.Footer links={footerLinks} /> | ||
</LoginCard.BasicLayout> | ||
</LoginPage.BasicLayout> | ||
</LoginPage.Container> | ||
); | ||
|
||
const LoginPage = props => ( | ||
<LoginPage.WithTranslation {...props}> | ||
<LoginPage.Pattern /> | ||
</LoginPage.WithTranslation> | ||
); | ||
|
||
LoginPage.Container = Container; | ||
LoginPage.Header = Header; | ||
LoginPage.Footer = Footer; | ||
LoginPage.Card = LoginCard; | ||
LoginPage.FooterLinks = FooterLinks; | ||
LoginPage.WithTranslation = WithTranslation; | ||
LoginPage.Alert = LoginPageAlert; | ||
LoginPage.Pattern = LoginPagePattern; | ||
LoginPage.Social = SocialLoginPage; | ||
LoginPage.SocialContainer = SocialLoginPageContainer; | ||
LoginPage.BasicLayout = BasicLoginPageLayout; | ||
LoginPage.Link = LoginPageLink; | ||
|
||
LoginPagePattern.propTypes = { | ||
container: PropTypes.shape({ ...LoginPage.Container.propTypes }), | ||
header: PropTypes.shape({ ...LoginPage.Header.propTypes }), | ||
card: PropTypes.shape({ | ||
...LoginCard.LanguagePicker.propTypes, | ||
...LoginCard.Form.propTypes, | ||
...LoginCard.SignUp.propTypes, | ||
...LoginCard.RememberMe.propTypes, | ||
...LoginCard.ForgotPassword.propTypes | ||
}), | ||
footerLinks: PropTypes.array | ||
}; | ||
|
||
LoginPagePattern.defaultProps = { | ||
container: { ...LoginPage.Container.defaultProps }, | ||
header: { ...LoginPage.Header.defaultProps }, | ||
card: { | ||
...LoginCard.LanguagePicker.defaultProps, | ||
...LoginCard.Form.defaultProps, | ||
...LoginCard.SignUp.defaultProps, | ||
...LoginCard.RememberMe.defaultProps, | ||
...LoginCard.ForgotPassword.defaultProps | ||
}, | ||
footerLinks: [...LoginPage.Footer.defaultProps.links] | ||
}; | ||
|
||
LoginPage.propTypes = { ...LoginPagePattern.propTypes }; | ||
LoginPage.defaultProps = { ...LoginPagePattern.defaultProps }; | ||
|
||
export default LoginPage; |
238 changes: 238 additions & 0 deletions
238
packages/patternfly-react/src/components/LoginPage/LoginPage.stories.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
import React from 'react'; | ||
import { storiesOf } from '@storybook/react'; | ||
import { withKnobs, number } from '@storybook/addon-knobs'; | ||
import { action } from '@storybook/addon-actions'; | ||
import { defaultTemplate } from 'storybook/decorators/storyTemplates'; | ||
import { | ||
storybookPackageName, | ||
STORYBOOK_CATEGORY, | ||
DOCUMENTATION_URL | ||
} from 'storybook/constants/siteConstants'; | ||
import LoginPage from './LoginPage'; | ||
import englishMessages from './mocks/messages.en'; | ||
import frenchMessages from './mocks/messages.fr'; | ||
import images from './assets/img'; | ||
import { name } from '../../../package.json'; | ||
|
||
const stories = storiesOf( | ||
`${storybookPackageName(name)}/${ | ||
STORYBOOK_CATEGORY.APPLICATION_FRAMEWORK | ||
}/Login Page`, | ||
module | ||
); | ||
|
||
stories.addDecorator(withKnobs); | ||
stories.addDecorator( | ||
defaultTemplate({ | ||
title: 'Login Page', | ||
documentationLink: `${ | ||
DOCUMENTATION_URL.PATTERNFLY_ORG_APP_FRAMEWORK | ||
}login-page` | ||
}) | ||
); | ||
|
||
const storyAction = (e, message) => { | ||
e.preventDefault(); | ||
action(message)(); | ||
}; | ||
|
||
const createProps = () => { | ||
const { header, footerLinks, card } = englishMessages; | ||
footerLinks.forEach(link => { | ||
link.onClick = e => storyAction(e, 'Footer Link was pressed'); | ||
}); | ||
return { | ||
container: { | ||
backgroundUrl: images.background, | ||
translations: { en: englishMessages, fr: frenchMessages }, | ||
className: '', | ||
alert: { | ||
message: header.alert, | ||
onDismiss: e => storyAction(e, 'Notification was dismissed'), | ||
show: true | ||
} | ||
}, | ||
header: { | ||
logoSrc: images.brand, | ||
logoTitle: header.logo, | ||
caption: header.caption | ||
}, | ||
footerLinks, | ||
card: { | ||
title: card.header.title, | ||
selectedLanguage: card.header.selectedLanguage, | ||
availableLanguages: card.header.availableLanguages, | ||
signUp: { | ||
label: card.signUp.label, | ||
link: { | ||
children: card.signUp.link.label, | ||
href: '#', | ||
onClick: e => storyAction(e, 'sign up was clicked') | ||
} | ||
}, | ||
form: { | ||
validate: true, | ||
submitError: card.form.error, | ||
showError: true, | ||
usernameField: { | ||
id: 'card_email', | ||
type: 'email', | ||
placeholder: card.usernameField.placeholder, | ||
errors: card.usernameField.errors, | ||
error: card.usernameField.errors.invalid, | ||
showError: true | ||
}, | ||
passwordField: { | ||
id: 'card_password', | ||
type: 'password', | ||
placeholder: card.passwordField.placeholder, | ||
minLength: 8, | ||
errors: card.passwordField.errors, | ||
warnings: card.passwordField.warnings, | ||
warning: card.passwordField.warnings.capsLock, | ||
showWarning: true | ||
}, | ||
additionalFields: null, | ||
rememberMe: { | ||
label: card.rememberMe, | ||
onClick: e => action('remember me checkbox was clicked')() | ||
}, | ||
forgotPassword: { | ||
label: card.forgotPassword, | ||
href: '#', | ||
onClick: e => storyAction(e, 'Forgot password was clicked') | ||
}, | ||
disableSubmit: false, | ||
submitText: card.form.submitText, | ||
onSubmit: e => storyAction(e, 'Form was submitted') | ||
}, | ||
social: { | ||
links: createLogoList() | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
const createLogoList = () => { | ||
const socialLinkClick = e => storyAction(e, 'Social Link was clicked'); | ||
const { | ||
google, | ||
facebook, | ||
linkedin, | ||
github, | ||
instagram, | ||
stackExchange, | ||
twitter, | ||
git, | ||
openID, | ||
dropbox, | ||
fedora, | ||
skype | ||
} = images; | ||
return [ | ||
{ | ||
src: google, | ||
alt: 'Google', | ||
text: 'Google', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: facebook, | ||
alt: 'Facebook', | ||
text: 'Facebook', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: linkedin, | ||
alt: 'Linkedin', | ||
text: 'Linkedin', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: github, | ||
alt: 'Github', | ||
text: 'Github', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: instagram, | ||
alt: 'Instagram', | ||
text: 'Instagram', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: git, | ||
alt: 'Git', | ||
text: 'Git', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: openID, | ||
alt: 'OpenID', | ||
text: 'OpenID', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: dropbox, | ||
alt: 'Dropbox', | ||
text: 'Dropbox', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: fedora, | ||
alt: 'Fedora', | ||
text: 'Fedora', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: skype, | ||
alt: 'Skype', | ||
text: 'Skype', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: twitter, | ||
alt: 'Twitter', | ||
text: 'Twitter', | ||
onClick: e => socialLinkClick(e) | ||
}, | ||
{ | ||
src: stackExchange, | ||
alt: 'StackExchange', | ||
text: 'StackExchange', | ||
onClick: e => socialLinkClick(e) | ||
} | ||
]; | ||
}; | ||
|
||
stories.addWithInfo('Managed Basic Login Page', () => ( | ||
<LoginPage {...createProps()} /> | ||
)); | ||
|
||
stories.addWithInfo('Build Your own Basic Login Page', () => { | ||
const props = { ...createProps() }; | ||
props.card.form.validate = false; | ||
return LoginPage.Pattern(props); | ||
}); | ||
|
||
stories.addWithInfo('Managed Social Login Page', () => { | ||
const logoListCopy = createLogoList(); | ||
const listSize = number('Social List Size', 12); | ||
const socialLinks = logoListCopy.splice(0, listSize); | ||
|
||
const props = { ...createProps() }; | ||
props.card.social.links = socialLinks; | ||
|
||
return <LoginPage.Social {...props} />; | ||
}); | ||
|
||
stories.addWithInfo('Build Your own Social Login Page', () => { | ||
const logoListCopy = createLogoList(); | ||
const listSize = number('Social List Size', 12); | ||
const socialLinks = logoListCopy.splice(0, listSize); | ||
|
||
const props = { ...createProps() }; | ||
props.card.social.links = socialLinks; | ||
props.card.form.validate = false; | ||
return LoginPage.Social.Pattern(props); | ||
}); |
Oops, something went wrong.