mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(ui) disabled fields mapped from the sso
This commit is contained in:
parent
b9b8150e28
commit
55e76e1523
@ -93,7 +93,7 @@ export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, Fab
|
||||
<>
|
||||
{label && <label onClick={focusEditor} className="fab-textEditor-label">{label}</label>}
|
||||
<div className="fab-textEditor">
|
||||
<MenuBar editor={editor} paragraphTools={paragraphTools} video={video} image={image} />
|
||||
<MenuBar editor={editor} paragraphTools={paragraphTools} video={video} image={image} disabled={readOnly} />
|
||||
<EditorContent editor={editor} />
|
||||
<div className="fab-textEditor-character-count">
|
||||
{editor?.storage.characterCount.characters()} / {limit}
|
||||
|
@ -9,12 +9,13 @@ interface MenuBarProps {
|
||||
paragraphTools?: boolean,
|
||||
video?: boolean,
|
||||
image?: boolean,
|
||||
disabled?: boolean,
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is the menu bar for the WYSIWYG text editor
|
||||
*/
|
||||
export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video, image }) => {
|
||||
export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video, image, disabled = false }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
const [submenu, setSubmenu] = useState('');
|
||||
@ -140,12 +141,13 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='fab-textEditor-menu'>
|
||||
<div className={`fab-textEditor-menu ${disabled ? 'fab-textEditor-menu--disabled' : ''}`}>
|
||||
{ paragraphTools &&
|
||||
(<>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
<TextAa size={24} />
|
||||
@ -153,6 +155,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
<ListBullets size={24} />
|
||||
@ -160,6 +163,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
<Quotes size={24} />
|
||||
@ -170,6 +174,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
<TextBolder size={24} />
|
||||
@ -177,6 +182,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
<TextItalic size={24} />
|
||||
@ -184,6 +190,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => editor.chain().focus().toggleUnderline().run()}
|
||||
disabled={disabled}
|
||||
className={editor.isActive('underline') ? 'is-active' : ''}
|
||||
>
|
||||
<TextUnderline size={24} />
|
||||
@ -191,6 +198,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => toggleSubmenu('link')}
|
||||
disabled={disabled}
|
||||
className={`ignore-onclickoutside ${editor.isActive('link') ? 'is-active' : ''}`}
|
||||
>
|
||||
<LinkSimpleHorizontal size={24} />
|
||||
@ -200,6 +208,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
(<>
|
||||
<button
|
||||
type='button'
|
||||
disabled={disabled}
|
||||
onClick={() => toggleSubmenu('video')}
|
||||
>
|
||||
<VideoCamera size={24} />
|
||||
@ -210,6 +219,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({ editor, paragraphTools, video,
|
||||
(<>
|
||||
<button
|
||||
type='button'
|
||||
disabled={disabled}
|
||||
onClick={() => toggleSubmenu('image')}
|
||||
>
|
||||
<Image size={24} />
|
||||
|
@ -12,10 +12,11 @@ interface EditSocialsProps<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
setValue: UseFormSetValue<User>,
|
||||
networks: SocialNetwork[],
|
||||
formState: FormState<TFieldValues>
|
||||
formState: FormState<TFieldValues>,
|
||||
disabled: boolean|((id: string) => boolean),
|
||||
}
|
||||
|
||||
export const EditSocials = <TFieldValues extends FieldValues>({ register, setValue, networks, formState }: EditSocialsProps<TFieldValues>) => {
|
||||
export const EditSocials = <TFieldValues extends FieldValues>({ register, setValue, networks, formState, disabled }: EditSocialsProps<TFieldValues>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
// regular expression to validate the the input fields
|
||||
const urlRegex = /^(https?:\/\/)([\da-z.-]+)\.([-a-z\d.]{2,30})([/\w .-]*)*\/?$/;
|
||||
@ -66,6 +67,7 @@ export const EditSocials = <TFieldValues extends FieldValues>({ register, setVal
|
||||
formState={formState}
|
||||
defaultValue={network.url}
|
||||
label={network.name}
|
||||
disabled={disabled}
|
||||
placeholder={t('app.shared.text_editor.url_placeholder')}
|
||||
icon={<img src={`${Icons}#${network.name}`}></img>}
|
||||
addOn={<Trash size={16} />}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { UseFormRegister } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { FieldPath } from 'react-hook-form/dist/types/path';
|
||||
@ -6,26 +6,39 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface GenderInputProps<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
disabled?: boolean|((id: string) => boolean),
|
||||
}
|
||||
|
||||
/**
|
||||
* Input component to set the gender for the user
|
||||
*/
|
||||
export const GenderInput = <TFieldValues extends FieldValues>({ register }: GenderInputProps<TFieldValues>) => {
|
||||
export const GenderInput = <TFieldValues extends FieldValues>({ register, disabled = false }: GenderInputProps<TFieldValues>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof disabled === 'function') {
|
||||
setIsDisabled(disabled('statistic_profile_attributes.gender'));
|
||||
} else {
|
||||
setIsDisabled(disabled);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
return (
|
||||
<div className="gender-input">
|
||||
<label>
|
||||
<p>{t('app.shared.gender_input.man')}</p>
|
||||
<input type="radio"
|
||||
value="true"
|
||||
disabled={isDisabled}
|
||||
{...register('statistic_profile_attributes.gender' as FieldPath<TFieldValues>)} />
|
||||
</label>
|
||||
<label>
|
||||
<p>{t('app.shared.gender_input.woman')}</p>
|
||||
<input type="radio"
|
||||
value="false"
|
||||
disabled={isDisabled}
|
||||
{...register('statistic_profile_attributes.gender' as FieldPath<TFieldValues>)} />
|
||||
</label>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { SubmitHandler, useForm, useWatch } from 'react-hook-form';
|
||||
import { isNil as _isNil } from 'lodash';
|
||||
@ -17,6 +17,7 @@ import { AvatarInput } from './avatar-input';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import { EditSocials } from '../socials/edit-socials';
|
||||
import UserLib from '../../lib/user';
|
||||
import AuthProviderAPI from '../../api/auth-provider';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -39,7 +40,14 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
const { handleSubmit, register, control, formState, setValue } = useForm<User>({ defaultValues: { ...user } });
|
||||
const output = useWatch<User>({ control });
|
||||
|
||||
const [isOrganization, setIsOrganization] = React.useState<boolean>(!_isNil(user.invoicing_profile_attributes.organization_attributes));
|
||||
const [isOrganization, setIsOrganization] = useState<boolean>(!_isNil(user.invoicing_profile_attributes.organization_attributes));
|
||||
const [isLocalDatabaseProvider, setIsLocalDatabaseProvider] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
AuthProviderAPI.active().then(data => {
|
||||
setIsLocalDatabaseProvider(data.providable_type === 'DatabaseProvider');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Callback triggered when the form is submitted: process with the user creation or update.
|
||||
@ -54,7 +62,10 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
* Check if the given field path should be disabled because it's mapped to the SSO API.
|
||||
*/
|
||||
const isDisabled = function (id: string) {
|
||||
// TODO: check if AuthenticationProvider is not LocalDatabase
|
||||
if (isLocalDatabaseProvider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.mapped_from_sso?.includes(UserFieldMapping[id]);
|
||||
};
|
||||
|
||||
@ -72,7 +83,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
<div className="fields-group">
|
||||
<div className="personnal-data">
|
||||
<h4>{t('app.shared.user_profile_form.personal_data')}</h4>
|
||||
<GenderInput register={register} />
|
||||
<GenderInput register={register} disabled={isDisabled} />
|
||||
<div className="names">
|
||||
<FormInput id="profile_attributes.last_name"
|
||||
register={register}
|
||||
@ -129,14 +140,15 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
disabled={isDisabled}
|
||||
formState={formState}
|
||||
label={t('app.shared.user_profile_form.email_address')} />
|
||||
{/* TODO: no password change if sso */}
|
||||
{action === 'update' && <ChangePassword register={register}
|
||||
onError={onError}
|
||||
currentFormPassword={output.password}
|
||||
formState={formState} />}
|
||||
{action === 'create' && <PasswordInput register={register}
|
||||
currentFormPassword={output.password}
|
||||
formState={formState} />}
|
||||
{isLocalDatabaseProvider && <div className="password">
|
||||
{ action === 'update' && <ChangePassword register={register}
|
||||
onError={onError}
|
||||
currentFormPassword={output.password}
|
||||
formState={formState} />}
|
||||
{action === 'create' && <PasswordInput register={register}
|
||||
currentFormPassword={output.password}
|
||||
formState={formState} />}
|
||||
</div>}
|
||||
</div>
|
||||
<div className="organization-data">
|
||||
<h4>{t('app.shared.user_profile_form.organization_data')}</h4>
|
||||
@ -145,6 +157,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
label={t('app.shared.user_profile_form.declare_organization')}
|
||||
tooltip={t('app.shared.user_profile_form.declare_organization_help')}
|
||||
defaultValue={isOrganization}
|
||||
disabled={isDisabled('invoicing_profile_attributes.organization_attributes.name')}
|
||||
onChange={setIsOrganization} />
|
||||
{isOrganization && <div className="organization-fields">
|
||||
<FormInput id="invoicing_profile_attributes.organization_attributes.id"
|
||||
@ -200,6 +213,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
<div className='account-networks'>
|
||||
<h4>{t('app.shared.user_profile_form.account_networks')}</h4>
|
||||
<EditSocials register={register}
|
||||
disabled={isDisabled}
|
||||
networks={userNetworks}
|
||||
setValue={setValue}
|
||||
formState={formState} />
|
||||
|
@ -45,6 +45,14 @@
|
||||
background-color: var(--gray-soft-dark);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
|
||||
button:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tiptap class for the editor
|
||||
|
Loading…
x
Reference in New Issue
Block a user