pl-fe: Allow reordering profile fields

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-09-27 22:21:21 +02:00
parent 9227eef670
commit b016dbec2b
4 changed files with 40 additions and 3 deletions

View file

@ -31,7 +31,10 @@ const spaces = {
8: 'gap-8', 8: 'gap-8',
}; };
interface IHStack extends Pick<React.HTMLAttributes<HTMLDivElement>, 'children' | 'className' | 'onClick' | 'style' | 'title'> { interface IHStack extends Pick<
React.HTMLAttributes<HTMLDivElement>,
'children' | 'className' | 'draggable' | 'onClick' | 'onDragEnd' | 'onDragEnter' | 'onDragStart' | 'style' | 'title'
> {
/** Vertical alignment of children. */ /** Vertical alignment of children. */
alignItems?: keyof typeof alignItemsOptions; alignItems?: keyof typeof alignItemsOptions;
/** Horizontal alignment of children. */ /** Horizontal alignment of children. */

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useRef } from 'react';
import { useIntl, defineMessages } from 'react-intl'; import { useIntl, defineMessages } from 'react-intl';
import Button from '../button/button'; import Button from '../button/button';
@ -39,6 +39,8 @@ interface IStreamfield {
minItems?: number; minItems?: number;
/** Maximum number of allowed inputs. */ /** Maximum number of allowed inputs. */
maxItems?: number; maxItems?: number;
/** Allow changing order of the items. */
draggable?: boolean;
} }
/** List of inputs that can be added or removed. */ /** List of inputs that can be added or removed. */
@ -52,9 +54,29 @@ const Streamfield: React.FC<IStreamfield> = ({
component: Component, component: Component,
maxItems = Infinity, maxItems = Infinity,
minItems = 0, minItems = 0,
draggable,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const dragItem = useRef<number | null>();
const dragOverItem = useRef<number | null>();
const handleDragStart = (i: number) => () => {
dragItem.current = i;
};
const handleDragEnter = (i: number) => () => {
dragOverItem.current = i;
};
const handleDragEnd = () => {
const newData = [...values];
const item = newData.splice(dragItem.current!, 1)[0];
newData.splice(dragOverItem.current!, 0, item);
onChange(newData);
};
const handleChange = (i: number) => (value: any) => { const handleChange = (i: number) => (value: any) => {
const newData = [...values]; const newData = [...values];
newData[i] = value; newData[i] = value;
@ -71,7 +93,15 @@ const Streamfield: React.FC<IStreamfield> = ({
{(values.length > 0) && ( {(values.length > 0) && (
<Stack space={1}> <Stack space={1}>
{values.map((value, i) => value?._destroy ? null : ( {values.map((value, i) => value?._destroy ? null : (
<HStack key={i} space={2} alignItems='center'> <HStack
key={i}
space={2}
alignItems='center'
draggable={draggable}
onDragStart={handleDragStart(i)}
onDragEnter={handleDragEnter(i)}
onDragEnd={handleDragEnd}
>
<Component <Component
key={i} key={i}
index={i} index={i}

View file

@ -452,6 +452,7 @@ const EditProfile: React.FC = () => {
onRemoveItem={handleRemoveField} onRemoveItem={handleRemoveField}
component={ProfileField} component={ProfileField}
maxItems={maxFields} maxItems={maxFields}
draggable
/> />
)} )}

View file

@ -288,6 +288,7 @@ const PlFeConfig: React.FC = () => {
onChange={handleStreamItemChange(['promoPanel', 'items'])} onChange={handleStreamItemChange(['promoPanel', 'items'])}
onAddItem={addStreamItem(['promoPanel', 'items'], templates.promoPanel)} onAddItem={addStreamItem(['promoPanel', 'items'], templates.promoPanel)}
onRemoveItem={deleteStreamItem(['promoPanel', 'items'])} onRemoveItem={deleteStreamItem(['promoPanel', 'items'])}
draggable
/> />
<Streamfield <Streamfield
@ -298,6 +299,7 @@ const PlFeConfig: React.FC = () => {
onChange={handleStreamItemChange(['navlinks', 'homeFooter'])} onChange={handleStreamItemChange(['navlinks', 'homeFooter'])}
onAddItem={addStreamItem(['navlinks', 'homeFooter'], templates.footerItem)} onAddItem={addStreamItem(['navlinks', 'homeFooter'], templates.footerItem)}
onRemoveItem={deleteStreamItem(['navlinks', 'homeFooter'])} onRemoveItem={deleteStreamItem(['navlinks', 'homeFooter'])}
draggable
/> />
<FormGroup labelText={intl.formatMessage(messages.copyrightFooterLabel)}> <FormGroup labelText={intl.formatMessage(messages.copyrightFooterLabel)}>
@ -347,6 +349,7 @@ const PlFeConfig: React.FC = () => {
onChange={handleStreamItemChange(['cryptoAddresses'])} onChange={handleStreamItemChange(['cryptoAddresses'])}
onAddItem={addStreamItem(['cryptoAddresses'], templates.cryptoAddress)} onAddItem={addStreamItem(['cryptoAddresses'], templates.cryptoAddress)}
onRemoveItem={deleteStreamItem(['cryptoAddresses'])} onRemoveItem={deleteStreamItem(['cryptoAddresses'])}
draggable
/> />
<FormGroup labelText={intl.formatMessage(messages.cryptoDonatePanelLimitLabel)}> <FormGroup labelText={intl.formatMessage(messages.cryptoDonatePanelLimitLabel)}>