mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-08 23:46:14 +01:00
92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
import React, { useState, useReducer } from 'react';
|
|
import { FormState, UseFormRegister, UseFormSetValue } from 'react-hook-form';
|
|
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
|
import { User } from '../../models/user';
|
|
import { SocialNetwork } from '../../models/social-network';
|
|
import Icons from '../../../../images/social-icons.svg';
|
|
import { FormInput } from '../form/form-input';
|
|
import { Trash } from 'phosphor-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
interface EditSocialsProps<TFieldValues> {
|
|
register: UseFormRegister<TFieldValues>,
|
|
setValue: UseFormSetValue<User>,
|
|
networks: SocialNetwork[],
|
|
formState: FormState<TFieldValues>,
|
|
disabled: boolean|((id: string) => boolean),
|
|
}
|
|
|
|
/**
|
|
* Allow a user to edit its personnal social networks
|
|
*/
|
|
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?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/;
|
|
|
|
const initSelectedNetworks = networks.filter(el => !['', null, undefined].includes(el.url));
|
|
const [selectedNetworks, setSelectedNetworks] = useState(initSelectedNetworks);
|
|
|
|
/**
|
|
* Callback triggered when the user adds a network, from the list of available networks, to the editable networks.
|
|
*/
|
|
const selectNetwork = (network) => {
|
|
setSelectedNetworks([...selectedNetworks, network]);
|
|
};
|
|
|
|
/**
|
|
* Return a derivated state of the selected networks list, depending on the given action.
|
|
*/
|
|
const reducer = (state, action) => {
|
|
switch (action.type) {
|
|
case 'delete':
|
|
setSelectedNetworks(selectedNetworks.filter(el => el !== action.payload.network));
|
|
setValue(action.payload.field, '');
|
|
return state.map(el => el === action.payload.network
|
|
? { ...el, url: '' }
|
|
: el);
|
|
case 'update':
|
|
return state.map(el => el === action.payload
|
|
? { ...el, url: action.payload.url }
|
|
: el);
|
|
default:
|
|
return state;
|
|
}
|
|
};
|
|
const [userNetworks, dispatch] = useReducer(reducer, networks);
|
|
|
|
return (
|
|
<>
|
|
<div className='social-icons'>
|
|
{userNetworks.map((network, index) =>
|
|
!selectedNetworks.includes(network) && <svg key={index} onClick={() => selectNetwork(network)} viewBox="0 0 24 24" >
|
|
<use href={`${Icons}#${network.name}`} />
|
|
</svg>
|
|
)}
|
|
</div>
|
|
{selectNetwork.length && <div className='social-inputs'>
|
|
{userNetworks.map((network, index) =>
|
|
selectedNetworks.includes(network) &&
|
|
<FormInput key={index}
|
|
id={`profile_attributes.${network.name}`}
|
|
register={register}
|
|
rules= {{
|
|
pattern: {
|
|
value: urlRegex,
|
|
message: t('app.shared.edit_socials.website_invalid')
|
|
}
|
|
}}
|
|
formState={formState}
|
|
defaultValue={network.url}
|
|
label={network.name}
|
|
disabled={disabled}
|
|
placeholder={t('app.shared.edit_socials.url_placeholder')}
|
|
icon={<svg viewBox="0 0 24 24"><use href={`${Icons}#${network.name}`}/></svg>}
|
|
addOn={<Trash size={16} />}
|
|
addOnAction={() => dispatch({ type: 'delete', payload: { network, field: `profile_attributes.${network.name}` } })} />
|
|
)}
|
|
</div>}
|
|
</>
|
|
);
|
|
};
|