1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-10 21:24:20 +01:00

(wip) show and edit social networks

This commit is contained in:
vincent 2022-04-28 17:31:31 +02:00
parent a5ff03334a
commit b34bab84e8
15 changed files with 274 additions and 25 deletions

View File

@ -0,0 +1,73 @@
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<defs><style> .nc-icon-wrapper { display: none } .nc-icon-wrapper:target { display: inline } </style></defs>
<svg viewBox="0 0 24 24">
<g id="lastfm" class="nc-icon-wrapper">
<path d="M20.25 1.5H3.75A2.25 2.25 0 0 0 1.5 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h16.5a2.25 2.25 0 0 0 2.25-2.25V3.75a2.25 2.25 0 0 0-2.25-2.25zm-4.322 14.667c-2.972 0-4.003-1.34-4.551-3.005-.764-2.39-1.008-3.951-2.954-3.951-1.05 0-2.114.755-2.114 2.869 0 1.65.844 2.68 2.03 2.68 1.34 0 2.231-.998 2.231-.998l.549 1.496s-.928.91-2.869.91c-2.405 0-3.745-1.412-3.745-4.023 0-2.714 1.34-4.312 3.867-4.312 3.445 0 3.787 1.94 4.725 4.776.412 1.257 1.134 2.166 2.869 2.166 1.167 0 1.786-.258 1.786-.895 0-.933-1.022-1.032-2.34-1.34-1.425-.343-1.992-1.084-1.992-2.25 0-1.876 1.514-2.457 3.057-2.457 1.753 0 2.817.637 2.953 2.184l-1.72.206c-.07-.74-.516-1.05-1.341-1.05-.755 0-1.219.343-1.219.929 0 .515.225.825.98.998 1.533.333 3.365.563 3.365 2.695.005 1.72-1.439 2.372-3.567 2.372z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="instagram" class="nc-icon-wrapper">
<path d="M12 9.5a2.5 2.5 0 1 0 .002 5 2.5 2.5 0 0 0-.002-5zm5.846-1.922a2.532 2.532 0 0 0-1.426-1.426c-.984-.388-3.328-.301-4.42-.301s-3.434-.09-4.42.301a2.531 2.531 0 0 0-1.426 1.426c-.388.984-.302 3.33-.302 4.421 0 1.092-.086 3.435.304 4.423a2.531 2.531 0 0 0 1.425 1.425c.984.389 3.328.302 4.42.302 1.094 0 3.434.09 4.421-.302a2.532 2.532 0 0 0 1.426-1.425c.391-.985.301-3.33.301-4.422 0-1.091.09-3.434-.301-4.422h-.002zM12 15.844a3.844 3.844 0 1 1 0-7.689 3.844 3.844 0 0 1 0 7.689zm4.002-6.952a.897.897 0 1 1 .002.002l-.002-.002zM20.25 1.5H3.75A2.25 2.25 0 0 0 1.5 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h16.5a2.25 2.25 0 0 0 2.25-2.25V3.75a2.25 2.25 0 0 0-2.25-2.25zm-.802 13.594c-.061 1.201-.335 2.266-1.212 3.14-.877.875-1.94 1.155-3.14 1.212-1.239.07-4.95.07-6.188 0-1.202-.06-2.263-.335-3.141-1.212-.878-.876-1.155-1.941-1.212-3.14-.07-1.239-.07-4.95 0-6.188.06-1.201.332-2.266 1.212-3.14.88-.875 1.944-1.152 3.14-1.209 1.239-.07 4.95-.07 6.188 0 1.202.06 2.266.335 3.14 1.212.876.876 1.155 1.941 1.213 3.143.07 1.234.07 4.942 0 6.182z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="github" class="nc-icon-wrapper">
<path d="M8.633 17.8c0 .082-.095.147-.214.147-.135.013-.23-.053-.23-.147 0-.082.095-.148.214-.148.123-.012.23.053.23.148zm-1.276-.185c-.029.082.053.176.176.201.107.041.23 0 .255-.082.024-.082-.054-.176-.177-.213-.106-.029-.225.012-.254.094zm1.813-.07c-.119.029-.201.107-.189.201.013.082.12.136.242.107.12-.029.201-.107.189-.189-.012-.078-.123-.131-.242-.119zm2.699-15.717c-5.69 0-10.04 4.32-10.04 10.008 0 4.549 2.862 8.441 6.951 9.81.525.095.71-.229.71-.495 0-.255-.012-1.657-.012-2.519 0 0-2.872.615-3.474-1.222 0 0-.468-1.194-1.14-1.501 0 0-.94-.644.065-.632 0 0 1.021.082 1.583 1.058.898 1.584 2.404 1.128 2.99.858.094-.657.361-1.112.656-1.383-2.292-.254-4.606-.586-4.606-4.532 0-1.128.312-1.694.968-2.416-.106-.266-.455-1.366.107-2.785.857-.266 2.83 1.108 2.83 1.108a9.636 9.636 0 0 1 2.576-.349c.873 0 1.755.12 2.576.349 0 0 1.972-1.378 2.83-1.108.562 1.424.213 2.519.106 2.785.657.726 1.058 1.292 1.058 2.416 0 3.958-2.415 4.274-4.708 4.532.377.324.697.94.697 1.903 0 1.383-.012 3.093-.012 3.43 0 .266.189.59.71.496 4.101-1.362 6.882-5.254 6.882-9.803 0-5.689-4.614-10.008-10.303-10.008zM5.815 15.974c-.053.041-.041.136.029.214.065.065.16.094.213.04.053-.04.04-.135-.029-.213-.065-.065-.16-.094-.213-.04zm-.443-.332c-.029.053.012.12.094.16.066.041.148.029.177-.029.028-.053-.013-.118-.095-.16-.082-.024-.147-.012-.176.03zm1.329 1.46c-.066.054-.041.177.053.255.094.094.213.106.267.04.053-.053.028-.176-.054-.254-.09-.094-.213-.106-.266-.04zm-.468-.603c-.065.041-.065.148 0 .242.066.095.177.136.23.095.066-.054.066-.16 0-.255-.058-.094-.164-.135-.23-.082z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="echosciences" class="nc-icon-wrapper">
<path d="M2.5 3.5v3.732h11.895V3.5H2.5zm4.298 10.289h6.494v-3.722H2.521V20.5h11.895v-3.727H6.798V13.79z" fill="currentColor" stroke="none"></path><path d="M18.213 3h-.7c2.221 2.704 3.458 5.722 3.456 8.905 0 3.252-1.295 6.336-3.616 9.095h.706c2.2-2.753 3.44-5.832 3.44-9.095.003-3.189-1.18-6.201-3.286-8.905z" fill="currentColor" stroke="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="flickr" class="nc-icon-wrapper">
<path d="M20.25 1.5H3.75A2.25 2.25 0 0 0 1.5 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h16.5a2.25 2.25 0 0 0 2.25-2.25V3.75a2.25 2.25 0 0 0-2.25-2.25zM8.273 14.953a2.975 2.975 0 0 1-2.976-2.976A2.975 2.975 0 0 1 8.273 9a2.975 2.975 0 0 1 2.977 2.977 2.975 2.975 0 0 1-2.977 2.976zm7.454 0a2.975 2.975 0 0 1-2.977-2.976A2.975 2.975 0 0 1 15.727 9a2.975 2.975 0 0 1 2.976 2.977 2.975 2.975 0 0 1-2.976 2.976z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="facebook" class="nc-icon-wrapper">
<path d="M22.172 12A10.17 10.17 0 0 0 12 1.828 10.17 10.17 0 0 0 1.828 12c0 5.077 3.72 9.285 8.583 10.049V14.94H7.827V12h2.584V9.759c0-2.55 1.517-3.957 3.842-3.957 1.113 0 2.277.198 2.277.198v2.502h-1.283c-1.264 0-1.658.784-1.658 1.589V12h2.821l-.45 2.94h-2.37v7.109c4.862-.764 8.582-4.972 8.582-10.049z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="youtube" class="nc-icon-wrapper">
<path d="M24.265 5.816a3.217 3.217 0 0 0-2.263-2.278C20.005 3 12 3 12 3s-8.005 0-10.002.538A3.217 3.217 0 0 0-.265 5.816C-.8 7.826-.8 12.018-.8 12.018s0 4.193.535 6.202c.294 1.109 1.162 1.945 2.263 2.242C3.995 21 12 21 12 21s8.005 0 10.002-.538c1.101-.297 1.969-1.133 2.263-2.242.535-2.01.535-6.202.535-6.202s0-4.192-.535-6.202zM9.382 15.825V8.212l6.69 3.806-6.69 3.807z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="vimeo" class="nc-icon-wrapper">
<path d="M20.4 1.5H3.6c-1.158 0-2.1.942-2.1 2.1v16.8c0 1.158.942 2.1 2.1 2.1h16.8c1.158 0 2.1-.942 2.1-2.1V3.6c0-1.158-.942-2.1-2.1-2.1zm-1.228 6.975c-.066 1.477-1.097 3.502-3.094 6.066-2.062 2.68-3.81 4.021-5.236 4.021-.886 0-1.631-.815-2.245-2.451-1.195-4.373-1.706-6.938-2.69-6.938-.113 0-.512.24-1.191.713l-.713-.919C5.752 7.43 7.42 5.723 8.466 5.63c1.18-.113 1.907.693 2.18 2.423.97 6.15 1.4 7.078 3.168 4.294.633-1.003.975-1.767 1.022-2.292.164-1.557-1.214-1.449-2.147-1.05.745-2.443 2.17-3.628 4.275-3.563 1.561.042 2.297 1.055 2.208 3.033z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="vimeo" class="nc-icon-wrapper">
<path d="M20.4 1.5H3.6c-1.158 0-2.1.942-2.1 2.1v16.8c0 1.158.942 2.1 2.1 2.1h16.8c1.158 0 2.1-.942 2.1-2.1V3.6c0-1.158-.942-2.1-2.1-2.1zm-1.228 6.975c-.066 1.477-1.097 3.502-3.094 6.066-2.062 2.68-3.81 4.021-5.236 4.021-.886 0-1.631-.815-2.245-2.451-1.195-4.373-1.706-6.938-2.69-6.938-.113 0-.512.24-1.191.713l-.713-.919C5.752 7.43 7.42 5.723 8.466 5.63c1.18-.113 1.907.693 2.18 2.423.97 6.15 1.4 7.078 3.168 4.294.633-1.003.975-1.767 1.022-2.292.164-1.557-1.214-1.449-2.147-1.05.745-2.443 2.17-3.628 4.275-3.563 1.561.042 2.297 1.055 2.208 3.033z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="viadeo" class="nc-icon-wrapper">
<path d="M20.25 1.5H3.75A2.25 2.25 0 0 0 1.5 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h16.5a2.25 2.25 0 0 0 2.25-2.25V3.75a2.25 2.25 0 0 0-2.25-2.25zm-5.592 16.369c-1.988 2.165-5.625 2.184-7.613 0-3.187-3.45-.928-9.192 3.807-9.192.623 0 1.246.098 1.832.314a3.749 3.749 0 0 0-.393 1.27 3.696 3.696 0 0 0-1.44-.281c-2.287 0-3.965 1.954-3.965 4.167 0 2.016 1.336 3.689 3.258 4.026 2.883-1.125 3.417-5.512 3.417-8.203 0-.342 0-.693-.028-1.036-.525-1.542-1.247-3.028-2.072-4.43 1.27.859 1.964 2.93 2.072 4.412v.018a10.15 10.15 0 0 1 .553 3.282c0 2.536-1.027 4.64-3.202 6.009l-.112.01c2.344.046 4.04-1.81 4.04-4.088a4.29 4.29 0 0 0-.323-1.674 3.763 3.763 0 0 0 1.238-.492 5.554 5.554 0 0 1-1.07 5.888zm1.326-6.914c-.623 0-1.176-.333-1.612-.755 1.026-.563 2.325-1.44 2.92-2.484.07-.141.192-.404.211-.563-.586 1.308-2.072 2.335-3.464 2.658a2.092 2.092 0 0 1-.351-1.14c0-.482.243-1.129.604-1.48 1.013-.961 2.485-.399 3.394-2.344 1.523 2.165.614 6.108-1.702 6.108z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="twitter" class="nc-icon-wrapper">
<path d="M20.25 1.5H3.75A2.25 2.25 0 0 0 1.5 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h16.5a2.25 2.25 0 0 0 2.25-2.25V3.75a2.25 2.25 0 0 0-2.25-2.25zm-2.292 7.444c.01.131.01.267.01.398 0 4.064-3.095 8.747-8.748 8.747a8.706 8.706 0 0 1-4.72-1.378c.248.028.487.037.74.037 1.44 0 2.762-.487 3.816-1.312a3.078 3.078 0 0 1-2.873-2.133c.473.07.9.07 1.387-.056a3.075 3.075 0 0 1-2.46-3.019v-.037c.407.23.885.37 1.387.389a3.068 3.068 0 0 1-1.369-2.56c0-.572.15-1.097.417-1.551a8.73 8.73 0 0 0 6.338 3.215c-.436-2.086 1.125-3.778 3-3.778.886 0 1.683.37 2.245.97a6.024 6.024 0 0 0 1.95-.74 3.066 3.066 0 0 1-1.35 1.692A6.117 6.117 0 0 0 19.5 7.35a6.471 6.471 0 0 1-1.542 1.594z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="pinterest" class="nc-icon-wrapper">
<path d="M22.172 12a10.17 10.17 0 0 1-13.183 9.717c.415-.677 1.034-1.785 1.264-2.666.123-.476.631-2.42.631-2.42.333.631 1.3 1.169 2.33 1.169 3.068 0 5.279-2.822 5.279-6.33 0-3.358-2.744-5.873-6.271-5.873-4.39 0-6.723 2.945-6.723 6.157 0 1.493.796 3.35 2.063 3.941.193.09.295.05.34-.135.033-.14.206-.833.284-1.152a.304.304 0 0 0-.07-.292c-.414-.512-.75-1.447-.75-2.321 0-2.244 1.697-4.413 4.593-4.413 2.498 0 4.25 1.702 4.25 4.138 0 2.752-1.391 4.66-3.2 4.66-.997 0-1.747-.825-1.505-1.838.287-1.21.84-2.514.84-3.388 0-.78-.418-1.431-1.287-1.431-1.022 0-1.842 1.054-1.842 2.469 0 .902.304 1.51.304 1.51s-1.005 4.257-1.19 5.052c-.205.878-.123 2.117-.037 2.92A10.176 10.176 0 0 1 1.828 12 10.17 10.17 0 0 1 12 1.828 10.17 10.17 0 0 1 22.172 12z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="linkedin" class="nc-icon-wrapper">
<path d="M21 1.5H2.995C2.17 1.5 1.5 2.18 1.5 3.014v17.972c0 .834.67 1.514 1.495 1.514H21c.825 0 1.5-.68 1.5-1.514V3.014A1.51 1.51 0 0 0 21 1.5zm-13.153 18H4.734V9.478h3.118V19.5h-.005zM6.29 8.11a1.805 1.805 0 0 1 0-3.61c.993 0 1.804.81 1.804 1.805 0 .998-.806 1.804-1.804 1.804zM19.514 19.5h-3.112v-4.875c0-1.162-.024-2.658-1.618-2.658-1.622 0-1.87 1.266-1.87 2.574V19.5H9.802V9.478h2.986v1.369h.042c.417-.788 1.434-1.617 2.948-1.617 3.15 0 3.736 2.076 3.736 4.776V19.5z" fill="currentColor"></path>
</g>
</svg>
<svg viewBox="0 0 24 24">
<g id="dailymotion" class="nc-icon-wrapper">
<path d="M15.512 12.516a2.269 2.269 0 0 0-1.142-.291c-.62 0-1.142.207-1.567.622-.425.414-.638.936-.638 1.566 0 .661.208 1.202.623 1.622.415.42.937.63 1.566.63.641 0 1.174-.215 1.6-.646.425-.43.638-.966.64-1.606a2.21 2.21 0 0 0-.286-1.1 2.069 2.069 0 0 0-.796-.797zM1.5 1.5v21h21v-21h-21zm17.564 17.497h-2.488v-1.12h-.032c-.493.819-1.365 1.228-2.615 1.228-.86 0-1.625-.205-2.291-.614a4.139 4.139 0 0 1-1.544-1.677c-.363-.709-.544-1.504-.544-2.385 0-.862.184-1.646.552-2.354.35-.69.884-1.271 1.543-1.678.662-.409 1.408-.613 2.237-.614a3.79 3.79 0 0 1 1.394.245c.415.162.806.428 1.172.796V7.172l2.615-.567.002 12.392z" fill="currentColor"></path>
</g>
</svg>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -9,6 +9,7 @@ import { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';
interface FormInputProps<TFieldValues, TInputType> extends FormComponent<TFieldValues>, AbstractFormItemProps<TFieldValues> {
icon?: ReactNode,
addOn?: ReactNode,
addOnAction?: (event: React.MouseEvent<HTMLButtonElement>) => void,
addOnClassName?: string,
debounce?: number,
type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week' | 'hidden',
@ -21,7 +22,7 @@ interface FormInputProps<TFieldValues, TInputType> extends FormComponent<TFieldV
/**
* This component is a template for an input component to use within React Hook Form
*/
export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, register, label, tooltip, defaultValue, icon, className, rules, readOnly, disabled, type, addOn, addOnClassName, placeholder, error, warning, formState, step, onChange, debounce }: FormInputProps<TFieldValues, TInputType>) => {
export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, register, label, tooltip, defaultValue, icon, className, rules, readOnly, disabled, type, addOn, addOnAction, addOnClassName, placeholder, error, warning, formState, step, onChange, debounce }: FormInputProps<TFieldValues, TInputType>) => {
/**
* Debounced (ie. temporised) version of the 'on change' callback.
*/
@ -65,7 +66,7 @@ export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, re
disabled={disabled}
readOnly={readOnly}
placeholder={placeholder} />
{addOn && <span className={`addon ${addOnClassName || ''}`}>{addOn}</span>}
{addOn && <span onClick={addOnAction} className={`addon ${addOnClassName || ''} ${addOnAction ? 'is-btn' : ''}`}>{addOn}</span>}
</AbstractFormItem>
);
};

View File

@ -0,0 +1,67 @@
import React, { useState, useReducer } from 'react';
import { UseFormRegister, UseFormResetField } 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>,
resetField: UseFormResetField<User>,
networks: SocialNetwork[],
}
export const EditSocials = <TFieldValues extends FieldValues>({ register, resetField, networks }: EditSocialsProps<TFieldValues>) => {
const { t } = useTranslation('shared');
const initSelectedNetworks = networks.filter(el => el.url !== '');
const [selectedNetworks, setSelectedNetworks] = useState(initSelectedNetworks);
const selectNetwork = (network) => {
setSelectedNetworks([...selectedNetworks, network]);
};
const reducer = (state, action) => {
switch (action.type) {
case 'delete':
setSelectedNetworks(selectedNetworks.filter(el => el !== action.payload.network));
resetField(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) && <img key={index} src={`${Icons}#${network.name}`} onClick={() => selectNetwork(network)}></img>
)}
</div>
<div>
{userNetworks.map((network, index) =>
selectedNetworks.includes(network) &&
<FormInput key={index}
id={`profile.${network.name}`}
register={register}
defaultValue={network.url}
label={network.name}
placeholder={t('app.shared.text_editor.url_placeholder')}
icon={<img src={`${Icons}#${network.name}`}></img>}
addOn={<Trash size={16} />}
addOnAction={() => dispatch({ type: 'delete', payload: { network, field: `profile.${network.name}` } })} />
)}
</div>
</>
);
};

View File

@ -0,0 +1,41 @@
import React from 'react';
import { SocialNetwork } from '../../models/social-network';
import Icons from '../../../../images/social-icons.svg';
import { IApplication } from '../../models/application';
import { Loader } from '../base/loader';
import { react2angular } from 'react2angular';
declare const Application: IApplication;
interface SocialsProps {
networks: SocialNetwork[]
}
const plop = [{
name: 'facebook',
url: 'https://plop.com'
}, {
name: 'linkedin',
url: 'https://plop.com'
}];
export const Socials: React.FC<SocialsProps> = ({ networks = plop }) => {
return (
<div className='social-icons'>
{networks.map((network, index) =>
<a key={index} href={network.url}>
<img src={`${Icons}#${network.name}`}></img>
</a>
)}
</div>
);
};
const SocialsWrapper: React.FC<SocialsProps> = (props) => {
return (
<Loader>
<Socials {...props} />
</Loader>
);
};
Application.Components.component('socials', react2angular(SocialsWrapper, ['networks']));

View File

@ -11,6 +11,8 @@ import { GenderInput } from './gender-input';
import { ChangePassword } from './change-password';
import Switch from 'react-switch';
import { PasswordInput } from './password-input';
import { EditSocials } from '../socials/edit-socials';
import UserLib from '../../lib/user';
declare const Application: IApplication;
@ -25,7 +27,7 @@ interface UserProfileFormProps {
export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size, user, className, onError }) => {
const { t } = useTranslation('shared');
const { handleSubmit, register, control, formState } = useForm<User>({ defaultValues: { ...user } });
const { handleSubmit, register, resetField, control, formState } = useForm<User>({ defaultValues: { ...user } });
const output = useWatch<User>({ control });
const [isOrganization, setIsOrganization] = React.useState<boolean>(user.invoicing_profile.organization !== null);
@ -37,6 +39,8 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
console.log(action, data);
};
const userNetworks = new UserLib(user).getSocialNetworks(user);
return (
<form className={`user-profile-form user-profile-form--${size} ${className}`} onSubmit={handleSubmit(onSubmit)}>
<div className="avatar-group">
@ -104,6 +108,12 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
currentFormPassword={output.password}
formState={formState} />}
</div>
<div className='account-networks'>
<h4>{t('app.shared.user_profile_form.account_networks')}</h4>
<EditSocials register={register}
networks={userNetworks}
resetField={resetField} />
</div>
<div className="organization-data">
<h4>{t('app.shared.user_profile_form.organization_data')}</h4>
<label className="organization-toggle">

View File

@ -19,4 +19,17 @@ export default class UserLib {
return false;
};
/**
* Filter social networks from the user's profile
*/
getSocialNetworks = (customer: User): {name: string, url: string, active: boolean}[] => {
const userNetworks = [];
const supportedNetworks = ['facebook', 'twitter', 'viadeo', 'linkedin', 'instagram', 'youtube', 'vimeo', 'dailymotion', 'github', 'echosciences', 'pinterest', 'lastfm', 'flickr'];
for (const [name, url] of Object.entries(customer.profile)) {
supportedNetworks.includes(name) && userNetworks.push({ name, url });
}
return userNetworks;
};
}

View File

@ -0,0 +1,4 @@
export interface SocialNetwork {
name: string,
url: string
}

View File

@ -0,0 +1,5 @@
declare module '*.svg' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const value: any;
export default value;
}

View File

@ -566,17 +566,34 @@ body.container {
// profile edition -- add a social network buttons
.social-icons {
& > div {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 1.6rem;
& > * {
cursor: pointer;
padding: 0.2em;
width: 3em;
display: inline-block;
text-align: center;
height: 3em;
display: flex;
justify-content: center;
align-items: center;
border-radius: 3px;
border: 1px solid transparent;
overflow: hidden;
}
& > img {
border: 1px solid var(--gray-soft-dark);
background-color: var(--gray-soft-lightest);
&:hover {
border: 1px solid $border-color;
border-color: var(--secondary);
background-color: var(--secondary);
}
}
& > a {
&:hover { box-shadow: 0 0 0 1px var(--main); }
img {
max-width: 100%;
height: inherit;
}
}
}

View File

@ -58,6 +58,7 @@
border: 1px solid var(--gray-soft-dark);
border-radius: var(--border-radius);
transition: border-color ease-in-out 0.15s;
overflow: hidden;
.icon,
.addon {
@ -71,12 +72,24 @@
.icon {
grid-area: icon;
border-right: 1px solid var(--gray-soft-dark);
& > * {
max-width: 24px;
max-height: 24px;
}
}
.addon {
grid-area: addon;
border-left: 1px solid var(--gray-soft-dark);
&.is-btn:hover {
cursor: pointer;
filter: brightness(90%);
}
}
& > input {
grid-area: field;
border: none;
border-radius: var(--border-radius);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .08);
padding: 0 0.8rem;
color: var(--gray-hard-darkest);
@ -123,11 +136,6 @@
color: var(--gray-soft-darkest);
}
}
.addon {
grid-area: addon;
border-left: 1px solid var(--gray-soft-dark);
}
}
&.is-incorrect &-field {
border-color: var(--error);

View File

@ -20,6 +20,7 @@
<p ng-show="privacyPolicy.value">
<a ui-sref="app.public.privacy" translate>{{ 'app.public.about.privacy_policy' }}</a>
</p>
<socials />
</div>
<div class="col-sm-offset-0 col-md-offset-0 col-lg-offset-1 col-sm-4 col-md-4" ng-show="aboutContacts.value">

View File

@ -37,6 +37,7 @@ en:
add_an_avatar: "Add an avatar"
personal_data: "Personal"
account_data: "Account"
account_networks: "Social networks"
organization_data: "Organization"
declare_organization: "I am an organization"
pseudonym: "Nickname"

View File

@ -0,0 +1,4 @@
module.exports = {
test: /\.svg$/i,
type: 'asset'
};

View File

@ -9,6 +9,7 @@ const sassErb = require('./modules/sass_erb');
const html = require('./modules/html');
const uiTour = require('./modules/ui-tour');
const hmr = require('./modules/hmr');
const svg = require('./modules/svg');
const isDevelopment = process.env.NODE_ENV !== 'production';
@ -44,7 +45,8 @@ const customConfig = {
html,
sass,
uiTour,
hmr
hmr,
svg
]
},
resolve: {

View File

@ -19,8 +19,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
enable_extension "unaccent"
create_table "abuses", id: :serial, force: :cascade do |t|
t.integer "signaled_id"
t.string "signaled_type"
t.integer "signaled_id"
t.string "first_name"
t.string "last_name"
t.string "email"
@ -49,8 +49,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
t.string "locality"
t.string "country"
t.string "postal_code"
t.integer "placeable_id"
t.string "placeable_type"
t.integer "placeable_id"
t.datetime "created_at"
t.datetime "updated_at"
end
@ -64,8 +64,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
end
create_table "assets", id: :serial, force: :cascade do |t|
t.integer "viewable_id"
t.string "viewable_type"
t.integer "viewable_id"
t.string "attachment"
t.string "type"
t.datetime "created_at"
@ -146,8 +146,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
end
create_table "credits", id: :serial, force: :cascade do |t|
t.integer "creditable_id"
t.string "creditable_type"
t.integer "creditable_id"
t.integer "plan_id"
t.integer "hours"
t.datetime "created_at"
@ -369,15 +369,15 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
create_table "notifications", id: :serial, force: :cascade do |t|
t.integer "receiver_id"
t.integer "attached_object_id"
t.string "attached_object_type"
t.integer "attached_object_id"
t.integer "notification_type_id"
t.boolean "is_read", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "receiver_type"
t.boolean "is_send", default: false
t.jsonb "meta_data", default: {}
t.jsonb "meta_data", default: "{}"
t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id"
t.index ["receiver_id"], name: "index_notifications_on_receiver_id"
end
@ -423,6 +423,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
t.boolean "send_scope_to_token_endpoint"
t.string "post_logout_redirect_uri"
t.string "uid_field"
t.string "extra_authorize_params"
t.string "allow_authorize_params"
t.string "client__identifier"
t.string "client__secret"
t.string "client__redirect_uri"
@ -570,8 +572,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
create_table "prices", id: :serial, force: :cascade do |t|
t.integer "group_id"
t.integer "plan_id"
t.integer "priceable_id"
t.string "priceable_type"
t.integer "priceable_id"
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -681,8 +683,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
t.text "message"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "reservable_id"
t.string "reservable_type"
t.integer "reservable_id"
t.integer "nb_reserve_places"
t.integer "statistic_profile_id"
t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id"
@ -691,8 +693,8 @@ ActiveRecord::Schema.define(version: 2022_04_25_095244) do
create_table "roles", id: :serial, force: :cascade do |t|
t.string "name"
t.integer "resource_id"
t.string "resource_type"
t.integer "resource_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"