mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
refactored settings screen
This commit is contained in:
parent
001bdbb196
commit
d55222b3ad
8 changed files with 294 additions and 225 deletions
29
src/components/containers/Zone/index.tsx
Normal file
29
src/components/containers/Zone/index.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import React, { FC } from "react";
|
||||||
|
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import styles from "./styles.module.scss";
|
||||||
|
|
||||||
|
interface ZoneProps {
|
||||||
|
title?: string;
|
||||||
|
className?: string;
|
||||||
|
color?: "danger" | "normal";
|
||||||
|
}
|
||||||
|
|
||||||
|
const Zone: FC<ZoneProps> = ({
|
||||||
|
title,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
color = "normal",
|
||||||
|
}) => (
|
||||||
|
<div className={classNames(className, styles.pad, styles[color])}>
|
||||||
|
{!!title && (
|
||||||
|
<div className={styles.title}>
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export { Zone };
|
36
src/components/containers/Zone/styles.module.scss
Normal file
36
src/components/containers/Zone/styles.module.scss
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
@import "src/styles/variables";
|
||||||
|
|
||||||
|
$pad_danger: mix($red, $content_bg, 70%);
|
||||||
|
$pad_usual: mix(white, $content_bg, 10%);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
left: $radius;
|
||||||
|
transform: translate(0, -100%);
|
||||||
|
background: $pad_usual;
|
||||||
|
border-radius: 4px;
|
||||||
|
font: $font_10_semibold;
|
||||||
|
line-height: 12px;
|
||||||
|
padding: 2px $gap * 0.5;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
.danger & {
|
||||||
|
background: $pad_danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad {
|
||||||
|
padding: $gap * 1.5 $gap $gap;
|
||||||
|
box-shadow: inset $pad_usual 0 0 0 2px;
|
||||||
|
border-radius: $radius;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
box-shadow: inset $pad_danger 0 0 0 2px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,156 +1,37 @@
|
||||||
import React, { FC } from 'react';
|
import { FC } from "react";
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import { Filler } from "~/components/containers/Filler";
|
||||||
|
import { Group } from "~/components/containers/Group";
|
||||||
|
import { Padder } from "~/components/containers/Padder";
|
||||||
|
import { Button } from "~/components/input/Button";
|
||||||
|
import { UserSettingsView } from "~/containers/settings/UserSettingsView";
|
||||||
|
import {
|
||||||
|
SettingsProvider,
|
||||||
|
useSettings,
|
||||||
|
} from "~/utils/providers/SettingsProvider";
|
||||||
|
|
||||||
import { Superpower } from '~/components/boris/Superpower';
|
const Form = ({ children }) => {
|
||||||
import { Filler } from '~/components/containers/Filler';
|
const { handleSubmit } = useSettings();
|
||||||
import { Group } from '~/components/containers/Group';
|
|
||||||
import { Button } from '~/components/input/Button';
|
|
||||||
import { InputText } from '~/components/input/InputText';
|
|
||||||
import { Textarea } from '~/components/input/Textarea';
|
|
||||||
import { ERROR_LITERAL } from '~/constants/errors';
|
|
||||||
import { ProfileAccounts } from '~/containers/profile/ProfileAccounts';
|
|
||||||
import { usePatchUser } from '~/hooks/auth/usePatchUser';
|
|
||||||
import { useUser } from '~/hooks/auth/useUser';
|
|
||||||
import { useSettingsForm } from '~/utils/providers/SettingsProvider';
|
|
||||||
import { has } from '~/utils/ramda';
|
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
return <form onSubmit={handleSubmit}>{children}</form>;
|
||||||
|
};
|
||||||
const getError = (error?: string) => (error && has(error, ERROR_LITERAL) ? error : undefined);
|
|
||||||
|
|
||||||
const ProfileSettings: FC = () => {
|
const ProfileSettings: FC = () => {
|
||||||
const { user } = useUser();
|
|
||||||
const { save } = usePatchUser();
|
|
||||||
|
|
||||||
const { handleSubmit, values, errors, handleChange } = useSettingsForm(
|
|
||||||
{ ...user, password: '', newPassword: '' },
|
|
||||||
save
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.wrap} onSubmit={handleSubmit}>
|
<SettingsProvider>
|
||||||
|
<Form>
|
||||||
|
<Padder>
|
||||||
<Group>
|
<Group>
|
||||||
<Group horizontal className={styles.base_info}>
|
<UserSettingsView />
|
||||||
<Superpower>
|
|
||||||
<div className={classNames(styles.avatar, styles.pad)}>
|
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>Фото</span>
|
|
||||||
<small>Будет здесь. Кстати, ты видишь это, потому что включил суперсилы в Борисе.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Superpower>
|
|
||||||
|
|
||||||
<Group className={styles.pad}>
|
<Group horizontal>
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>О себе</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
value={values.fullname}
|
|
||||||
handler={handleChange('fullname')}
|
|
||||||
title="Полное имя"
|
|
||||||
error={getError(errors.fullname)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
value={values.description}
|
|
||||||
handler={handleChange('description')}
|
|
||||||
title="Описание"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={styles.small}>
|
|
||||||
Описание будет показываться при клике наведении на вашу аватарку.
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Superpower>
|
|
||||||
<div className={styles.pad}>
|
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>Обложка</span>
|
|
||||||
<small>Будет здесь. Кстати, ты видишь это, потому что включил суперсилы в Борисе.</small>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Superpower>
|
|
||||||
|
|
||||||
<Filler />
|
|
||||||
|
|
||||||
<Group className={classNames(styles.pad, styles.pad_danger)}>
|
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>Логин и пароли</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
value={values.username}
|
|
||||||
handler={handleChange('username')}
|
|
||||||
title="Логин"
|
|
||||||
error={getError(errors.username)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
value={values.email}
|
|
||||||
handler={handleChange('email')}
|
|
||||||
title="E-mail"
|
|
||||||
error={getError(errors.email)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
value={values.newPassword}
|
|
||||||
handler={handleChange('newPassword')}
|
|
||||||
title="Новый пароль"
|
|
||||||
type="password"
|
|
||||||
error={getError(errors.newPassword)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
value={values.password}
|
|
||||||
handler={handleChange('password')}
|
|
||||||
title="Старый пароль"
|
|
||||||
type="password"
|
|
||||||
error={getError(errors.password)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={styles.small}>
|
|
||||||
Чтобы изменить любое из этих полей, нужно ввести старый пароль.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Filler />
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Filler />
|
|
||||||
|
|
||||||
<Filler />
|
|
||||||
|
|
||||||
<div className={styles.pad}>
|
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>Аккаунты</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ProfileAccounts />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Superpower>
|
|
||||||
<div className={styles.pad}>
|
|
||||||
<div className={styles.pad__title}>
|
|
||||||
<span>Всякие приятные штуковины</span>
|
|
||||||
<small>Будут здесь. Кстати, ты видишь это, потому что включил суперсилы в Борисе.</small>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Superpower>
|
|
||||||
|
|
||||||
<Group horizontal className={styles.buttons}>
|
|
||||||
<Filler />
|
<Filler />
|
||||||
<Button title="Сохранить" type="submit" />
|
<Button title="Сохранить" type="submit" />
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</form>
|
</Padder>
|
||||||
|
</Form>
|
||||||
|
</SettingsProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
@import "src/styles/variables";
|
|
||||||
|
|
||||||
$pad_danger: mix($red, $content_bg, 70%);
|
|
||||||
$pad_usual: mix(white, $content_bg, 10%);
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
padding: $gap;
|
|
||||||
z-index: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pad {
|
|
||||||
padding: $gap * 1.5 $gap $gap;
|
|
||||||
box-shadow: inset $pad_usual 0 0 0 2px;
|
|
||||||
border-radius: $radius;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&_danger {
|
|
||||||
box-shadow: inset $pad_danger 0 0 0 2px;
|
|
||||||
|
|
||||||
.pad__title {
|
|
||||||
span {
|
|
||||||
background: $pad_danger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
span {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
left: $radius;
|
|
||||||
transform: translate(0, -100%);
|
|
||||||
background: $pad_usual;
|
|
||||||
border-radius: 4px;
|
|
||||||
font: $font_10_semibold;
|
|
||||||
line-height: 12px;
|
|
||||||
padding: 2px $gap * 0.5;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.small {
|
|
||||||
font: $font_12_regular;
|
|
||||||
padding: 0 $gap 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
}
|
|
||||||
|
|
||||||
div.base_info.base_info {
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
flex: 0 0 150px;
|
|
||||||
}
|
|
|
@ -1,34 +1,58 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from "react";
|
||||||
|
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from "~/components/containers/Filler";
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from "~/components/input/Button";
|
||||||
import { ProfileSettings } from '~/components/profile/ProfileSettings';
|
import { ProfileSettings } from "~/components/profile/ProfileSettings";
|
||||||
import { useStackContext } from '~/components/sidebar/SidebarStack';
|
import { useStackContext } from "~/components/sidebar/SidebarStack";
|
||||||
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
import { SidebarStackCard } from "~/components/sidebar/SidebarStackCard";
|
||||||
|
import { UserSettingsView } from "~/containers/settings/UserSettingsView";
|
||||||
|
import {
|
||||||
|
SettingsProvider,
|
||||||
|
useSettings,
|
||||||
|
} from "~/utils/providers/SettingsProvider";
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
import styles from "./styles.module.scss";
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
|
const Form = ({ children, className }) => {
|
||||||
|
const { handleSubmit } = useSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit} className={className}>
|
||||||
|
{children}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const ProfileSidebarSettings: FC<IProps> = () => {
|
const ProfileSidebarSettings: FC<IProps> = () => {
|
||||||
const { closeAllTabs } = useStackContext();
|
const { closeAllTabs } = useStackContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarStackCard width={600} headerFeature="back" title="Настройки" onBackPress={closeAllTabs}>
|
<SidebarStackCard
|
||||||
<div className={styles.wrap}>
|
width={600}
|
||||||
|
headerFeature="back"
|
||||||
|
title="Настройки"
|
||||||
|
onBackPress={closeAllTabs}
|
||||||
|
>
|
||||||
|
<SettingsProvider>
|
||||||
|
<Form className={styles.wrap}>
|
||||||
<div className={styles.scroller}>
|
<div className={styles.scroller}>
|
||||||
<ProfileSettings />
|
<UserSettingsView />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.buttons}>
|
<div className={styles.buttons}>
|
||||||
<Filler />
|
<Filler />
|
||||||
<Button color="outline" onClick={closeAllTabs}>
|
<Button color="link" onClick={closeAllTabs}>
|
||||||
Отмена
|
Отмена
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button color="secondary">Сохранить</Button>
|
<Button color="secondary" type="submit">
|
||||||
</div>
|
Сохранить
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
</Form>
|
||||||
|
</SettingsProvider>
|
||||||
</SidebarStackCard>
|
</SidebarStackCard>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
133
src/containers/settings/UserSettingsView/index.tsx
Normal file
133
src/containers/settings/UserSettingsView/index.tsx
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
import { Superpower } from "~/components/boris/Superpower";
|
||||||
|
import { Filler } from "~/components/containers/Filler";
|
||||||
|
import { Group } from "~/components/containers/Group";
|
||||||
|
import { Zone } from "~/components/containers/Zone";
|
||||||
|
import { InputText } from "~/components/input/InputText";
|
||||||
|
import { Textarea } from "~/components/input/Textarea";
|
||||||
|
import { ERROR_LITERAL } from "~/constants/errors";
|
||||||
|
import { ProfileAccounts } from "~/containers/profile/ProfileAccounts";
|
||||||
|
import { useSettings } from "~/utils/providers/SettingsProvider";
|
||||||
|
import { has } from "~/utils/ramda";
|
||||||
|
|
||||||
|
import styles from "./styles.module.scss";
|
||||||
|
|
||||||
|
interface UserSettingsViewProps {}
|
||||||
|
|
||||||
|
const getError = (error?: string) =>
|
||||||
|
error && has(error, ERROR_LITERAL) ? error : undefined;
|
||||||
|
|
||||||
|
const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
||||||
|
const { values, handleChange, errors } = useSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group>
|
||||||
|
<Group horizontal className={styles.base_info}>
|
||||||
|
<Superpower>
|
||||||
|
<Zone className={styles.avatar} title="Фото">
|
||||||
|
<small>
|
||||||
|
Будет здесь. Кстати, ты видишь это, потому что включил суперсилы в
|
||||||
|
Борисе.
|
||||||
|
</small>
|
||||||
|
</Zone>
|
||||||
|
</Superpower>
|
||||||
|
|
||||||
|
<Zone title="О себе">
|
||||||
|
<Group>
|
||||||
|
<InputText
|
||||||
|
value={values.fullname}
|
||||||
|
handler={handleChange("fullname")}
|
||||||
|
title="Полное имя"
|
||||||
|
error={getError(errors.fullname)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
value={values.description}
|
||||||
|
handler={handleChange("description")}
|
||||||
|
title="Описание"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.small}>
|
||||||
|
Описание будет показываться при клике наведении на вашу аватарку.
|
||||||
|
</div>
|
||||||
|
</Group>
|
||||||
|
</Zone>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Superpower>
|
||||||
|
<Zone title="Обложка">
|
||||||
|
<small>
|
||||||
|
Будет здесь. Кстати, ты видишь это, потому что включил суперсилы в
|
||||||
|
Борисе.
|
||||||
|
</small>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</Zone>
|
||||||
|
</Superpower>
|
||||||
|
|
||||||
|
<Filler />
|
||||||
|
|
||||||
|
<Zone color="danger" title="Логин и пароли">
|
||||||
|
<Group>
|
||||||
|
<InputText
|
||||||
|
value={values.username}
|
||||||
|
handler={handleChange("username")}
|
||||||
|
title="Логин"
|
||||||
|
error={getError(errors.username)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputText
|
||||||
|
value={values.email}
|
||||||
|
handler={handleChange("email")}
|
||||||
|
title="E-mail"
|
||||||
|
error={getError(errors.email)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputText
|
||||||
|
value={values.newPassword}
|
||||||
|
handler={handleChange("newPassword")}
|
||||||
|
title="Новый пароль"
|
||||||
|
type="password"
|
||||||
|
error={getError(errors.newPassword)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputText
|
||||||
|
value={values.password}
|
||||||
|
handler={handleChange("password")}
|
||||||
|
title="Старый пароль"
|
||||||
|
type="password"
|
||||||
|
error={getError(errors.password)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.small}>
|
||||||
|
Чтобы изменить любое из этих полей, нужно ввести старый пароль.
|
||||||
|
</div>
|
||||||
|
</Group>
|
||||||
|
</Zone>
|
||||||
|
|
||||||
|
<Filler />
|
||||||
|
|
||||||
|
<Filler />
|
||||||
|
|
||||||
|
<Zone className={styles.pad} title="Аккаунты">
|
||||||
|
<ProfileAccounts />
|
||||||
|
</Zone>
|
||||||
|
|
||||||
|
<Superpower>
|
||||||
|
<Zone title="Всякие приятные штуковины">
|
||||||
|
<small>
|
||||||
|
Будут здесь. Кстати, ты видишь это, потому что включил суперсилы в
|
||||||
|
Борисе.
|
||||||
|
</small>
|
||||||
|
<br />
|
||||||
|
</Zone>
|
||||||
|
</Superpower>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { UserSettingsView };
|
25
src/containers/settings/UserSettingsView/styles.module.scss
Normal file
25
src/containers/settings/UserSettingsView/styles.module.scss
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
@import "src/styles/variables";
|
||||||
|
|
||||||
|
$pad_danger: mix($red, $content_bg, 70%);
|
||||||
|
$pad_usual: mix(white, $content_bg, 10%);
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
padding: $gap;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font: $font_12_regular;
|
||||||
|
padding: 0 $gap 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
}
|
||||||
|
|
||||||
|
div.base_info.base_info {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex: 0 0 150px;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue