-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added basic login screen and functions
- Loading branch information
Showing
16 changed files
with
363 additions
and
15 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -1,6 +1,17 @@ | ||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' | ||
import type { RootState } from '@Pimcore/components/login-form/store' | ||
|
||
export const api = createApi({ | ||
baseQuery: fetchBaseQuery({ baseUrl: '/' }), | ||
baseQuery: fetchBaseQuery({ | ||
baseUrl: '/', | ||
prepareHeaders: (headers, { getState }) => { | ||
// By default, if we have a token in the store, let's use that for authenticated requests | ||
const token = (getState() as RootState).auth?.token | ||
if (token !== null) { | ||
headers.set('authorization', `Bearer ${token}`) | ||
} | ||
return headers | ||
} | ||
}), | ||
endpoints: () => ({}) | ||
}) |
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,37 @@ | ||
import { createSlice } from '@reduxjs/toolkit' | ||
import type { PayloadAction } from '@reduxjs/toolkit' | ||
import { type User } from '@Pimcore/components/login-form/services/auth' | ||
import { type RootState } from '@Pimcore/components/login-form/store' | ||
|
||
interface AuthState { | ||
user: User | null | ||
token: string | null | ||
} | ||
|
||
const initialState: AuthState = { | ||
user: null, | ||
token: null | ||
|
||
} | ||
|
||
const slice = createSlice({ | ||
name: 'auth', | ||
initialState, | ||
reducers: { | ||
setCredentials: ( | ||
state, | ||
{ | ||
payload: { user, token } | ||
}: PayloadAction<{ user: User, token: string }> | ||
) => { | ||
state.user = user | ||
state.token = token | ||
} | ||
} | ||
}) | ||
|
||
export const { setCredentials } = slice.actions | ||
|
||
export const authReducer = slice.reducer | ||
|
||
export const selectCurrentUser = (state: RootState): User | null => state.auth.user |
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,9 @@ | ||
import { useMemo } from 'react' | ||
import { useSelector } from 'react-redux' | ||
import {selectCurrentUser} from "@Pimcore/app/auth/authSlice"; | ||
|
||
export const useAuth = () => { | ||
const user = useSelector(selectCurrentUser) | ||
|
||
return useMemo(() => ({ user }), [user]) | ||
} |
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,43 @@ | ||
import { createStyles } from 'antd-style' | ||
|
||
export const useStyle = createStyles(({ token, css }) => { | ||
return { | ||
form: css` | ||
form { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 8px; | ||
font-family: Lato, sans-serif; | ||
font-size: 12px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 22px; | ||
.flex-space { | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
} | ||
.ant-btn-link { | ||
color: ${token.colorPrimary}; | ||
&:hover { | ||
color: ${token.colorPrimaryHover}; | ||
} | ||
} | ||
} | ||
.login__additional-logins { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
gap: 8px; | ||
.ant-btn { | ||
width: 100%; | ||
} | ||
} | ||
` | ||
} | ||
}) |
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,96 @@ | ||
import { Button, Checkbox, Input } from 'antd' | ||
import React from 'react' | ||
import { EyeInvisibleOutlined, EyeTwoTone, UserOutlined } from '@ant-design/icons' | ||
import { useStyle } from '@Pimcore/components/login-form/login-form-style' | ||
import { type LoginRequest, useLoginMutation } from '@Pimcore/components/login-form/services/auth' | ||
import { useDispatch } from 'react-redux' | ||
import { setCredentials } from '@Pimcore/app/auth/authSlice' | ||
import { useMessage } from '@Pimcore/components/message/useMessage' | ||
|
||
export interface IAdditionalLogins { | ||
key: string | ||
name: string | ||
link: string | ||
} | ||
|
||
interface ILoginFormProps { | ||
additionalLogins?: IAdditionalLogins[] | ||
} | ||
|
||
export const LoginForm = ({ additionalLogins }: ILoginFormProps): React.JSX.Element => { | ||
const dispatch = useDispatch() | ||
const { styles } = useStyle() | ||
const [messageApi, contextHolder] = useMessage() | ||
|
||
const [formState, setFormState] = React.useState<LoginRequest>({ | ||
username: '', | ||
password: '' | ||
}) | ||
|
||
const [login, { isLoading }] = useLoginMutation() | ||
|
||
const handleAuthentication = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => { | ||
try { | ||
e.preventDefault() | ||
const user = await login(formState).unwrap() | ||
dispatch(setCredentials(user)) | ||
|
||
console.log('worked', user) | ||
} catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
messageApi.error({ | ||
content: error.data.message | ||
}) | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
{contextHolder} | ||
<div className={ styles.form }> | ||
<form onSubmit={ handleAuthentication }> | ||
<Input | ||
onChange={ (e) => { setFormState({ ...formState, username: e.target.value }) } } | ||
placeholder="Username" | ||
prefix={ <UserOutlined /> } | ||
/> | ||
<Input.Password | ||
iconRender={ (visible) => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />) } | ||
onChange={ (e) => { setFormState({ ...formState, password: e.target.value }) } } | ||
placeholder="Password" | ||
/> | ||
<div className={ 'flex-space' }> | ||
<Checkbox> | ||
Remember me | ||
</Checkbox> | ||
<Button type={ 'link' }>Forgot password</Button> | ||
</div> | ||
|
||
<Button | ||
htmlType="submit" | ||
loading={ isLoading } | ||
type="primary" | ||
> | ||
Log in | ||
</Button> | ||
</form> | ||
|
||
{Array.isArray(additionalLogins) && ( | ||
<div className={ 'login__additional-logins' }> | ||
<p>or</p> | ||
|
||
{additionalLogins?.map((login) => ( | ||
<Button | ||
href={ login.link } | ||
key={ login.key } | ||
type={ 'primary' } | ||
> | ||
{login.name} | ||
</Button> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
</> | ||
) | ||
} |
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,37 @@ | ||
import { api } from '@Pimcore/app/api/pimcore' | ||
|
||
export interface User { | ||
username: string | ||
// token: string | ||
} | ||
|
||
export interface UserResponse { | ||
token: string | ||
lifetime: number | ||
user: User | ||
} | ||
|
||
export interface LoginRequest { | ||
username: string | ||
password: string | ||
} | ||
|
||
export const authApi = api | ||
.injectEndpoints({ | ||
endpoints: (builder) => ({ | ||
login: builder.mutation<UserResponse, LoginRequest>({ | ||
query: (credentials) => ({ | ||
url: 'studio/api/login', | ||
method: 'POST', | ||
body: credentials | ||
}) | ||
}), | ||
protected: builder.mutation<{ message: string }, undefined>({ | ||
query: () => 'protected' | ||
}) | ||
}), | ||
overrideExisting: false | ||
}) | ||
|
||
export { authApi as api } | ||
export const { useLoginMutation, useProtectedMutation } = authApi |
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,15 @@ | ||
import { configureStore } from '@reduxjs/toolkit' | ||
import { authReducer } from '@Pimcore/app/auth/authSlice'; | ||
import {api} from "@Pimcore/components/login-form/services/auth"; | ||
|
||
export const store = configureStore({ | ||
reducer: { | ||
[api.reducerPath]: api.reducer, | ||
auth: authReducer, | ||
}, | ||
middleware: (getDefaultMiddleware) => | ||
getDefaultMiddleware().concat(api.middleware), | ||
}) | ||
|
||
export type RootState = ReturnType<typeof store.getState> | ||
export type AppDispatch = typeof store.dispatch |
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
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
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,15 @@ | ||
import React from 'react' | ||
import { Background } from '@Pimcore/components/background/background' | ||
import { TranslationsLoaderContainer } from '@Pimcore/modules/app/translations/translations-loader-container' | ||
import { BaseLayoutView } from '@Pimcore/modules/app/base-layout/base-layout-view' | ||
|
||
export default function DefaultLayout (): React.JSX.Element { | ||
return ( | ||
<> | ||
<Background /> | ||
<TranslationsLoaderContainer> | ||
<BaseLayoutView /> | ||
</TranslationsLoaderContainer> | ||
</> | ||
) | ||
} |
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,64 @@ | ||
import React from 'react' | ||
import { createStyles } from 'antd-style' | ||
import { type IAdditionalLogins, LoginForm } from '@Pimcore/components/login-form/login-form' | ||
|
||
const useStyle = createStyles(({ token, css }) => { | ||
return { | ||
loginPage: css` | ||
display: flex; | ||
align-items: center; | ||
background: url(/bundles/pimcorestudioui/img/login-bg.png) lightgray 50% / cover no-repeat; | ||
position: absolute; | ||
inset: 0; | ||
overflow: hidden; | ||
`, | ||
loginWidget: css` | ||
display: flex; | ||
flex-direction: column; | ||
width: 503px; | ||
height: 608px; | ||
flex-shrink: 0; | ||
border-radius: 8px; | ||
background: linear-gradient(335deg, rgba(255, 255, 255, 0.86) 1.72%, rgba(57, 14, 97, 0.86) 158.36%); | ||
padding: 83px 100px 0 100px; | ||
margin-left: 80px; | ||
/* Component/Button/primaryShadow */ | ||
box-shadow: 0px 2px 0px 0px rgba(114, 46, 209, 0.10); | ||
img { | ||
margin-bottom: 50px | ||
} | ||
` | ||
} | ||
}) | ||
|
||
export default function LoginLayout (): React.JSX.Element { | ||
const { styles } = useStyle() | ||
const additionalLogins: IAdditionalLogins[] = [ | ||
{ | ||
key: 'google', | ||
name: 'Log in with Google', | ||
link: '/admin/login/google' | ||
}, | ||
{ | ||
key: 'github', | ||
name: 'Log in with GitHub', | ||
link: '/admin/login/github' | ||
} | ||
] | ||
|
||
return ( | ||
<div | ||
className={ styles.loginPage } | ||
> | ||
<div className={ styles.loginWidget }> | ||
<img | ||
alt={ 'Pimcore Logo' } | ||
src={ '/bundles/pimcorestudioui/img/logo.png' } | ||
/> | ||
<LoginForm additionalLogins={ additionalLogins } /> | ||
</div> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.