[Glitch] Profile editing: Add initial route
Port 4b1f66418b0173dd5edcfe9153e00dfe2e4ab948 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
925d1ffde5
commit
b8b1d3a934
@ -1,6 +1,8 @@
|
|||||||
import { forwardRef, useRef, useImperativeHandle } from 'react';
|
import { forwardRef, useRef, useImperativeHandle } from 'react';
|
||||||
import type { Ref } from 'react';
|
import type { Ref } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { scrollTop } from 'flavours/glitch/scroll';
|
import { scrollTop } from 'flavours/glitch/scroll';
|
||||||
|
|
||||||
export interface ColumnRef {
|
export interface ColumnRef {
|
||||||
@ -12,10 +14,11 @@ interface ColumnProps {
|
|||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
label?: string;
|
label?: string;
|
||||||
bindToDocument?: boolean;
|
bindToDocument?: boolean;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Column = forwardRef<ColumnRef, ColumnProps>(
|
export const Column = forwardRef<ColumnRef, ColumnProps>(
|
||||||
({ children, label, bindToDocument }, ref: Ref<ColumnRef>) => {
|
({ children, label, bindToDocument, className }, ref: Ref<ColumnRef>) => {
|
||||||
const nodeRef = useRef<HTMLDivElement>(null);
|
const nodeRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
@ -39,7 +42,12 @@ export const Column = forwardRef<ColumnRef, ColumnProps>(
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div role='region' aria-label={label} className='column' ref={nodeRef}>
|
<div
|
||||||
|
role='region'
|
||||||
|
aria-label={label}
|
||||||
|
className={classNames('column', className)}
|
||||||
|
ref={nodeRef}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -73,6 +73,7 @@ export interface Props {
|
|||||||
iconComponent?: IconProp;
|
iconComponent?: IconProp;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
multiColumn?: boolean;
|
multiColumn?: boolean;
|
||||||
extraButton?: React.ReactNode;
|
extraButton?: React.ReactNode;
|
||||||
@ -91,6 +92,7 @@ export const ColumnHeader: React.FC<Props> = ({
|
|||||||
iconComponent,
|
iconComponent,
|
||||||
active,
|
active,
|
||||||
children,
|
children,
|
||||||
|
className,
|
||||||
pinned,
|
pinned,
|
||||||
multiColumn,
|
multiColumn,
|
||||||
extraButton,
|
extraButton,
|
||||||
@ -141,7 +143,7 @@ export const ColumnHeader: React.FC<Props> = ({
|
|||||||
onPin?.();
|
onPin?.();
|
||||||
}, [history, pinned, onPin]);
|
}, [history, pinned, onPin]);
|
||||||
|
|
||||||
const wrapperClassName = classNames('column-header__wrapper', {
|
const wrapperClassName = classNames('column-header__wrapper', className, {
|
||||||
active,
|
active,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -256,7 +258,8 @@ export const ColumnHeader: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasIcon = icon && iconComponent;
|
const hasIcon = icon && iconComponent;
|
||||||
const hasTitle = hasIcon && title;
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||||
|
const hasTitle = (hasIcon || backButton) && title;
|
||||||
|
|
||||||
const component = (
|
const component = (
|
||||||
<div className={wrapperClassName}>
|
<div className={wrapperClassName}>
|
||||||
@ -270,7 +273,7 @@ export const ColumnHeader: React.FC<Props> = ({
|
|||||||
className='column-header__title'
|
className='column-header__title'
|
||||||
type='button'
|
type='button'
|
||||||
>
|
>
|
||||||
{!backButton && (
|
{!backButton && hasIcon && (
|
||||||
<Icon
|
<Icon
|
||||||
id={icon}
|
id={icon}
|
||||||
icon={iconComponent}
|
icon={iconComponent}
|
||||||
|
|||||||
@ -3,8 +3,10 @@ import { useCallback, useEffect } from 'react';
|
|||||||
import { useIntl, defineMessages } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { useIdentity } from '@/flavours/glitch/identity_context';
|
import { useIdentity } from '@/flavours/glitch/identity_context';
|
||||||
|
import { isClientFeatureEnabled } from '@/flavours/glitch/utils/environment';
|
||||||
import {
|
import {
|
||||||
fetchRelationships,
|
fetchRelationships,
|
||||||
followAccount,
|
followAccount,
|
||||||
@ -158,14 +160,24 @@ export const FollowButton: React.FC<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (accountId === me) {
|
if (accountId === me) {
|
||||||
|
const buttonClasses = classNames(className, 'button button-secondary', {
|
||||||
|
'button--compact': compact,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isClientFeatureEnabled('profile_editing')) {
|
||||||
|
return (
|
||||||
|
<Link to='/profile/edit' className={buttonClasses}>
|
||||||
|
{label}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href='/settings/profile'
|
href='/settings/profile'
|
||||||
target='_blank'
|
target='_blank'
|
||||||
rel='noopener'
|
rel='noopener'
|
||||||
className={classNames(className, 'button button-secondary', {
|
className={buttonClasses}
|
||||||
'button--compact': compact,
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { Column } from '@/flavours/glitch/components/column';
|
||||||
|
import { ColumnHeader } from '@/flavours/glitch/components/column_header';
|
||||||
|
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
|
||||||
|
import BundleColumnError from '@/flavours/glitch/features/ui/components/bundle_column_error';
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
|
|
||||||
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
|
export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||||
|
const accountId = useCurrentAccountId();
|
||||||
|
const account = useAccount(accountId);
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
if (!accountId) {
|
||||||
|
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
return (
|
||||||
|
<Column bindToDocument={!multiColumn} className={classes.column}>
|
||||||
|
<LoadingIndicator />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column bindToDocument={!multiColumn} className={classes.column}>
|
||||||
|
<ColumnHeader
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: 'account_edit.column_title',
|
||||||
|
defaultMessage: 'Edit Profile',
|
||||||
|
})}
|
||||||
|
className={classes.header}
|
||||||
|
showBackButton
|
||||||
|
extraButton={
|
||||||
|
<Link to={`/@${account.acct}`} className='button'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account_edit.column_button'
|
||||||
|
defaultMessage='Done'
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
.column {
|
||||||
|
border: 1px solid var(--color-border-primary);
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
:global(.column-header__buttons) {
|
||||||
|
align-items: center;
|
||||||
|
padding-inline-end: 16px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 24px 24px 12px;
|
||||||
|
|
||||||
|
> h1 {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,7 +25,7 @@ import { layoutFromWindow } from 'flavours/glitch/is_mobile';
|
|||||||
import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications';
|
import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications';
|
||||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||||
import { checkAnnualReport } from '@/flavours/glitch/reducers/slices/annual_report';
|
import { checkAnnualReport } from '@/flavours/glitch/reducers/slices/annual_report';
|
||||||
import { isServerFeatureEnabled } from '@/flavours/glitch/utils/environment';
|
import { isClientFeatureEnabled, isServerFeatureEnabled } from '@/flavours/glitch/utils/environment';
|
||||||
|
|
||||||
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
|
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
|
||||||
import { clearHeight } from '../../actions/height_cache';
|
import { clearHeight } from '../../actions/height_cache';
|
||||||
@ -83,6 +83,7 @@ import {
|
|||||||
TermsOfService,
|
TermsOfService,
|
||||||
AccountFeatured,
|
AccountFeatured,
|
||||||
AccountAbout,
|
AccountAbout,
|
||||||
|
AccountEdit,
|
||||||
Quotes,
|
Quotes,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
import { ColumnsContextProvider } from './util/columns_context';
|
import { ColumnsContextProvider } from './util/columns_context';
|
||||||
@ -240,6 +241,8 @@ class SwitchingColumnsArea extends PureComponent {
|
|||||||
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
||||||
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
||||||
|
|
||||||
|
{isClientFeatureEnabled('profile_editing') && <WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />}
|
||||||
|
|
||||||
<WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} />
|
<WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} />
|
||||||
<WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} />
|
<WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} />
|
||||||
<WrappedRoute path='/directory' component={Directory} content={children} />
|
<WrappedRoute path='/directory' component={Directory} content={children} />
|
||||||
|
|||||||
@ -92,6 +92,11 @@ export function AccountAbout() {
|
|||||||
.then((module) => ({ default: module.AccountAbout }));
|
.then((module) => ({ default: module.AccountAbout }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AccountEdit() {
|
||||||
|
return import('../../account_edit')
|
||||||
|
.then((module) => ({ default: module.AccountEdit }));
|
||||||
|
}
|
||||||
|
|
||||||
export function Followers () {
|
export function Followers () {
|
||||||
return import('../../followers');
|
return import('../../followers');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,3 +55,7 @@ export function useAccountId() {
|
|||||||
|
|
||||||
return accountId satisfies AccountId;
|
return accountId satisfies AccountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCurrentAccountId() {
|
||||||
|
return useAppSelector((state) => state.meta.get('me', null) as string | null);
|
||||||
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export function isServerFeatureEnabled(feature: ServerFeatures) {
|
|||||||
return initialState?.features.includes(feature) ?? false;
|
return initialState?.features.includes(feature) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientFeatures = 'collections';
|
type ClientFeatures = 'collections' | 'profile_editing';
|
||||||
|
|
||||||
export function isClientFeatureEnabled(feature: ClientFeatures) {
|
export function isClientFeatureEnabled(feature: ClientFeatures) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user