aboutsummaryrefslogtreecommitdiff
path: root/Timeline/ClientApp/src/app/user
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-07-13 20:59:52 +0800
committercrupest <crupest@outlook.com>2020-07-13 20:59:52 +0800
commite69190abb09661caa19fa3905a0d8f3b7e72648b (patch)
tree8030e6a2539347ccb12f0a6bbd31a1f390c6a7b7 /Timeline/ClientApp/src/app/user
parent0a7c884be668267003d7666b444f1022c99a7148 (diff)
downloadtimeline-e69190abb09661caa19fa3905a0d8f3b7e72648b.tar.gz
timeline-e69190abb09661caa19fa3905a0d8f3b7e72648b.tar.bz2
timeline-e69190abb09661caa19fa3905a0d8f3b7e72648b.zip
Move front end to a submodule.
Diffstat (limited to 'Timeline/ClientApp/src/app/user')
-rw-r--r--Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx306
-rw-r--r--Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx28
-rw-r--r--Timeline/ClientApp/src/app/user/Login.tsx147
-rw-r--r--Timeline/ClientApp/src/app/user/User.tsx79
-rw-r--r--Timeline/ClientApp/src/app/user/UserInfoCard.tsx116
-rw-r--r--Timeline/ClientApp/src/app/user/UserPage.tsx20
-rw-r--r--Timeline/ClientApp/src/app/user/api.ts79
-rw-r--r--Timeline/ClientApp/src/app/user/user-page.sass11
8 files changed, 0 insertions, 786 deletions
diff --git a/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx b/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx
deleted file mode 100644
index a0e56621..00000000
--- a/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx
+++ /dev/null
@@ -1,306 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { useTranslation } from 'react-i18next';
-import {
- Modal,
- ModalHeader,
- Row,
- Button,
- ModalBody,
- ModalFooter,
-} from 'reactstrap';
-import { AxiosError } from 'axios';
-
-import ImageCropper, { Clip, applyClipToImage } from '../common/ImageCropper';
-import { UiLogicError } from '../common';
-
-export interface ChangeAvatarDialogProps {
- open: boolean;
- close: () => void;
- process: (blob: Blob) => Promise<void>;
-}
-
-const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
- const { t } = useTranslation();
-
- const [file, setFile] = React.useState<File | null>(null);
- const [fileUrl, setFileUrl] = React.useState<string | null>(null);
- const [clip, setClip] = React.useState<Clip | null>(null);
- const [
- cropImgElement,
- setCropImgElement,
- ] = React.useState<HTMLImageElement | null>(null);
- const [resultBlob, setResultBlob] = React.useState<Blob | null>(null);
- const [resultUrl, setResultUrl] = React.useState<string | null>(null);
-
- const [state, setState] = React.useState<
- | 'select'
- | 'crop'
- | 'processcrop'
- | 'preview'
- | 'uploading'
- | 'success'
- | 'error'
- >('select');
-
- const [message, setMessage] = useState<
- string | { type: 'custom'; text: string } | null
- >('userPage.dialogChangeAvatar.prompt.select');
-
- const trueMessage =
- message == null
- ? null
- : typeof message === 'string'
- ? t(message)
- : message.text;
-
- const closeDialog = props.close;
-
- const toggle = React.useCallback((): void => {
- if (!(state === 'uploading')) {
- closeDialog();
- }
- }, [state, closeDialog]);
-
- useEffect(() => {
- if (file != null) {
- const url = URL.createObjectURL(file);
- setClip(null);
- setFileUrl(url);
- setState('crop');
- return () => {
- URL.revokeObjectURL(url);
- };
- } else {
- setFileUrl(null);
- setState('select');
- }
- }, [file]);
-
- React.useEffect(() => {
- if (resultBlob != null) {
- const url = URL.createObjectURL(resultBlob);
- setResultUrl(url);
- setState('preview');
- return () => {
- URL.revokeObjectURL(url);
- };
- } else {
- setResultUrl(null);
- }
- }, [resultBlob]);
-
- const onSelectFile = React.useCallback(
- (e: React.ChangeEvent<HTMLInputElement>): void => {
- const files = e.target.files;
- if (files == null || files.length === 0) {
- setFile(null);
- } else {
- setFile(files[0]);
- }
- },
- []
- );
-
- const onCropNext = React.useCallback(() => {
- if (
- cropImgElement == null ||
- clip == null ||
- clip.width === 0 ||
- file == null
- ) {
- throw new UiLogicError();
- }
-
- setState('processcrop');
- void applyClipToImage(cropImgElement, clip, file.type).then((b) => {
- setResultBlob(b);
- });
- }, [cropImgElement, clip, file]);
-
- const onCropPrevious = React.useCallback(() => {
- setFile(null);
- setState('select');
- }, []);
-
- const onPreviewPrevious = React.useCallback(() => {
- setResultBlob(null);
- setState('crop');
- }, []);
-
- const process = props.process;
-
- const upload = React.useCallback(() => {
- if (resultBlob == null) {
- throw new UiLogicError();
- }
-
- setState('uploading');
- process(resultBlob).then(
- () => {
- setState('success');
- },
- (e: unknown) => {
- setState('error');
- setMessage({ type: 'custom', text: (e as AxiosError).message });
- }
- );
- }, [resultBlob, process]);
-
- const createPreviewRow = (): React.ReactElement => {
- if (resultUrl == null) {
- throw new UiLogicError();
- }
- return (
- <Row className="justify-content-center">
- <img
- className="change-avatar-img"
- src={resultUrl}
- alt={t('userPage.dialogChangeAvatar.previewImgAlt')}
- />
- </Row>
- );
- };
-
- return (
- <Modal isOpen={props.open} toggle={toggle}>
- <ModalHeader> {t('userPage.dialogChangeAvatar.title')}</ModalHeader>
- {(() => {
- if (state === 'select') {
- return (
- <>
- <ModalBody className="container">
- <Row>{t('userPage.dialogChangeAvatar.prompt.select')}</Row>
- <Row>
- <input type="file" accept="image/*" onChange={onSelectFile} />
- </Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
- {t('operationDialog.cancel')}
- </Button>
- </ModalFooter>
- </>
- );
- } else if (state === 'crop') {
- if (fileUrl == null) {
- throw new UiLogicError();
- }
- return (
- <>
- <ModalBody className="container">
- <Row className="justify-content-center">
- <ImageCropper
- clip={clip}
- onChange={setClip}
- imageUrl={fileUrl}
- imageElementCallback={setCropImgElement}
- />
- </Row>
- <Row>{t('userPage.dialogChangeAvatar.prompt.crop')}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
- {t('operationDialog.cancel')}
- </Button>
- <Button color="secondary" onClick={onCropPrevious}>
- {t('operationDialog.previousStep')}
- </Button>
- <Button
- color="primary"
- onClick={onCropNext}
- disabled={
- cropImgElement == null || clip == null || clip.width === 0
- }
- >
- {t('operationDialog.nextStep')}
- </Button>
- </ModalFooter>
- </>
- );
- } else if (state === 'processcrop') {
- return (
- <>
- <ModalBody className="container">
- <Row>
- {t('userPage.dialogChangeAvatar.prompt.processingCrop')}
- </Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
- {t('operationDialog.cancel')}
- </Button>
- <Button color="secondary" onClick={onPreviewPrevious}>
- {t('operationDialog.previousStep')}
- </Button>
- </ModalFooter>
- </>
- );
- } else if (state === 'preview') {
- return (
- <>
- <ModalBody className="container">
- {createPreviewRow()}
- <Row>{t('userPage.dialogChangeAvatar.prompt.preview')}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
- {t('operationDialog.cancel')}
- </Button>
- <Button color="secondary" onClick={onPreviewPrevious}>
- {t('operationDialog.previousStep')}
- </Button>
- <Button color="primary" onClick={upload}>
- {t('userPage.dialogChangeAvatar.upload')}
- </Button>
- </ModalFooter>
- </>
- );
- } else if (state === 'uploading') {
- return (
- <>
- <ModalBody className="container">
- {createPreviewRow()}
- <Row>{t('userPage.dialogChangeAvatar.prompt.uploading')}</Row>
- </ModalBody>
- <ModalFooter></ModalFooter>
- </>
- );
- } else if (state === 'success') {
- return (
- <>
- <ModalBody className="container">
- <Row className="p-4 text-success">
- {t('operationDialog.success')}
- </Row>
- </ModalBody>
- <ModalFooter>
- <Button color="success" onClick={toggle}>
- {t('operationDialog.ok')}
- </Button>
- </ModalFooter>
- </>
- );
- } else {
- return (
- <>
- <ModalBody className="container">
- {createPreviewRow()}
- <Row className="text-danger">{trueMessage}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
- {t('operationDialog.cancel')}
- </Button>
- <Button color="primary" onClick={upload}>
- {t('operationDialog.retry')}
- </Button>
- </ModalFooter>
- </>
- );
- }
- })()}
- </Modal>
- );
-};
-
-export default ChangeAvatarDialog;
diff --git a/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx b/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx
deleted file mode 100644
index dbc216e1..00000000
--- a/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-
-import OperationDialog from '../common/OperationDialog';
-
-export interface ChangeNicknameDialogProps {
- open: boolean;
- close: () => void;
- onProcess: (newNickname: string) => Promise<void>;
-}
-
-const ChangeNicknameDialog: React.FC<ChangeNicknameDialogProps> = props => {
- return (
- <OperationDialog
- open={props.open}
- title="userPage.dialogChangeNickname.title"
- titleColor="default"
- inputScheme={[
- { type: 'text', label: 'userPage.dialogChangeNickname.inputLabel' }
- ]}
- onProcess={([newNickname]) => {
- return props.onProcess(newNickname as string);
- }}
- close={props.close}
- />
- );
-};
-
-export default ChangeNicknameDialog;
diff --git a/Timeline/ClientApp/src/app/user/Login.tsx b/Timeline/ClientApp/src/app/user/Login.tsx
deleted file mode 100644
index f8b3f0e7..00000000
--- a/Timeline/ClientApp/src/app/user/Login.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import React, { Fragment, useState, useEffect } from 'react';
-import { useHistory } from 'react-router';
-import { useTranslation } from 'react-i18next';
-import { AxiosError } from 'axios';
-
-import AppBar from '../common/AppBar';
-
-import { userLogin, useUser } from '../data/user';
-import {
- Label,
- FormGroup,
- Input,
- Form,
- FormFeedback,
- Spinner,
- Button,
-} from 'reactstrap';
-
-const Login: React.FC = (_) => {
- const { t } = useTranslation();
- const history = useHistory();
- const [username, setUsername] = useState<string>('');
- const [usernameDirty, setUsernameDirty] = useState<boolean>(false);
- const [password, setPassword] = useState<string>('');
- const [passwordDirty, setPasswordDirty] = useState<boolean>(false);
- const [rememberMe, setRememberMe] = useState<boolean>(true);
- const [process, setProcess] = useState<boolean>(false);
- const [error, setError] = useState<string | null>(null);
-
- const user = useUser();
-
- useEffect(() => {
- if (user != null) {
- const id = setTimeout(() => history.push('/'), 3000);
- return () => {
- clearTimeout(id);
- };
- }
- }, [history, user]);
-
- if (user != null) {
- return (
- <>
- <AppBar />
- <p className="mt-appbar">{t('login.alreadyLogin')}</p>
- </>
- );
- }
-
- function onSubmit(event: React.SyntheticEvent): void {
- if (username === '' || password === '') {
- setUsernameDirty(true);
- setPasswordDirty(true);
- return;
- }
-
- setProcess(true);
- userLogin(
- {
- username: username,
- password: password,
- },
- rememberMe
- ).then(
- (_) => {
- if (history.length === 0) {
- history.push('/');
- } else {
- history.goBack();
- }
- },
- (e: AxiosError | Error) => {
- setProcess(false);
- setError(e.message);
- }
- );
- event.preventDefault();
- }
-
- return (
- <Fragment>
- <AppBar />
- <div className="container login-container mt-appbar">
- <h1>{t('welcome')}</h1>
- <Form>
- <FormGroup>
- <Label for="username">{t('user.username')}</Label>
- <Input
- id="username"
- disabled={process}
- onChange={(e) => {
- setUsername(e.target.value);
- setUsernameDirty(true);
- }}
- value={username}
- invalid={usernameDirty && username === ''}
- />
- {usernameDirty && username === '' && (
- <FormFeedback>{t('login.emptyUsername')}</FormFeedback>
- )}
- </FormGroup>
- <FormGroup>
- <Label for="password">{t('user.password')}</Label>
- <Input
- id="password"
- type="password"
- disabled={process}
- onChange={(e) => {
- setPassword(e.target.value);
- setPasswordDirty(true);
- }}
- value={password}
- invalid={passwordDirty && password === ''}
- />
- {passwordDirty && password === '' && (
- <FormFeedback>{t('login.emptyPassword')}</FormFeedback>
- )}
- </FormGroup>
- <FormGroup check>
- <Input
- id="remember-me"
- type="checkbox"
- checked={rememberMe}
- onChange={(e) => {
- const v = (e.target as HTMLInputElement).checked;
- setRememberMe(v);
- }}
- />
- <Label for="remember-me">{t('user.rememberMe')}</Label>
- </FormGroup>
- {error ? <p className="text-error">{t(error)}</p> : null}
- <div>
- {process ? (
- <Spinner />
- ) : (
- <Button color="primary" onClick={onSubmit}>
- {t('user.login')}
- </Button>
- )}
- </div>
- </Form>
- </div>
- </Fragment>
- );
-};
-
-export default Login;
diff --git a/Timeline/ClientApp/src/app/user/User.tsx b/Timeline/ClientApp/src/app/user/User.tsx
deleted file mode 100644
index 0e1977b1..00000000
--- a/Timeline/ClientApp/src/app/user/User.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React, { useState } from 'react';
-import { useParams } from 'react-router';
-
-import { useUser } from '../data/user';
-import { changeNickname, changeAvatar } from './api';
-import { personalTimelineService } from '../data/timeline';
-
-import UserPage from './UserPage';
-import ChangeNicknameDialog from './ChangeNicknameDialog';
-import ChangeAvatarDialog from './ChangeAvatarDialog';
-import TimelinePageTemplate from '../timeline/TimelinePageTemplate';
-import { PersonalTimelineManageItem } from './UserInfoCard';
-import { UiLogicError } from '../common';
-
-const User: React.FC = (_) => {
- const { username } = useParams<{ username: string }>();
-
- const user = useUser();
-
- const [dialog, setDialog] = useState<null | PersonalTimelineManageItem>(null);
- const [dataKey, setDataKey] = useState<number>(0);
-
- let dialogElement: React.ReactElement | undefined;
-
- const closeDialogHandler = (): void => {
- setDialog(null);
- };
-
- if (dialog === 'nickname') {
- if (user == null) {
- throw new UiLogicError('Change nickname without login.');
- }
-
- dialogElement = (
- <ChangeNicknameDialog
- open
- close={closeDialogHandler}
- onProcess={(newNickname) => {
- const p = changeNickname(user.token, username, newNickname);
- return p.then((_) => {
- setDataKey(dataKey + 1);
- });
- }}
- />
- );
- } else if (dialog === 'avatar') {
- if (user == null) {
- throw new UiLogicError('Change avatar without login.');
- }
-
- dialogElement = (
- <ChangeAvatarDialog
- open
- close={closeDialogHandler}
- process={(file) => changeAvatar(user.token, username, file, file.type)}
- />
- );
- }
-
- const onManage = React.useCallback((item: PersonalTimelineManageItem) => {
- setDialog(item);
- }, []);
-
- return (
- <>
- <TimelinePageTemplate
- dataVersion={dataKey}
- name={username}
- UiComponent={UserPage}
- onManage={onManage}
- service={personalTimelineService}
- notFoundI18nKey="timeline.userNotExist"
- />
- {dialogElement}
- </>
- );
-};
-
-export default User;
diff --git a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx b/Timeline/ClientApp/src/app/user/UserInfoCard.tsx
deleted file mode 100644
index b4924a5d..00000000
--- a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import React from 'react';
-import clsx from 'clsx';
-import {
- Dropdown,
- DropdownToggle,
- DropdownMenu,
- DropdownItem,
- Button,
-} from 'reactstrap';
-import { useTranslation } from 'react-i18next';
-import { fromEvent } from 'rxjs';
-
-import {
- TimelineInfo,
- timelineVisibilityTooltipTranslationMap,
-} from '../data/timeline';
-import { useAvatarVersion, useAvatarUrlWithGivenVersion } from './api';
-import { useUser } from '../data/user';
-
-import { TimelineCardComponentProps } from '../timeline/TimelinePageTemplateUI';
-
-export type PersonalTimelineManageItem = 'avatar' | 'nickname';
-
-export type UserInfoCardProps = TimelineCardComponentProps<
- TimelineInfo,
- PersonalTimelineManageItem
->;
-
-const UserInfoCard: React.FC<UserInfoCardProps> = (props) => {
- const { onHeight, onManage } = props;
- const { t } = useTranslation();
- const user = useUser();
-
- const avatarVersion = useAvatarVersion();
- const avatarUrl = useAvatarUrlWithGivenVersion(
- user != null && user.username === props.timeline.owner.username
- ? avatarVersion
- : undefined,
- props.timeline.owner._links.avatar
- );
-
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const containerRef = React.useRef<HTMLDivElement>(null!);
-
- const notifyHeight = React.useCallback((): void => {
- if (onHeight) {
- onHeight(containerRef.current.getBoundingClientRect().height);
- }
- }, [onHeight]);
-
- React.useEffect(() => {
- const subscription = fromEvent(window, 'resize').subscribe(notifyHeight);
- return () => subscription.unsubscribe();
- });
-
- const [manageDropdownOpen, setManageDropdownOpen] = React.useState<boolean>(
- false
- );
- const toggleManageDropdown = React.useCallback(
- (): void => setManageDropdownOpen((old) => !old),
- []
- );
-
- return (
- <div
- ref={containerRef}
- className={clsx('rounded border bg-light p-2', props.className)}
- onTransitionEnd={notifyHeight}
- >
- <img
- src={avatarUrl}
- onLoad={notifyHeight}
- className="avatar large mr-2 mb-2 rounded-circle float-left"
- />
- <div>
- {props.timeline.owner.nickname}
- <small className="ml-3 text-secondary">
- @{props.timeline.owner.username}
- </small>
- </div>
- <p className="mb-0">{props.timeline.description}</p>
- <small className="mt-1 d-block">
- {t(timelineVisibilityTooltipTranslationMap[props.timeline.visibility])}
- </small>
- <div className="text-right mt-2">
- {onManage != null ? (
- <Dropdown isOpen={manageDropdownOpen} toggle={toggleManageDropdown}>
- <DropdownToggle outline color="primary">
- {t('timeline.manage')}
- </DropdownToggle>
- <DropdownMenu>
- <DropdownItem onClick={() => onManage('nickname')}>
- {t('timeline.manageItem.nickname')}
- </DropdownItem>
- <DropdownItem onClick={() => onManage('avatar')}>
- {t('timeline.manageItem.avatar')}
- </DropdownItem>
- <DropdownItem onClick={() => onManage('property')}>
- {t('timeline.manageItem.property')}
- </DropdownItem>
- <DropdownItem onClick={props.onMember}>
- {t('timeline.manageItem.member')}
- </DropdownItem>
- </DropdownMenu>
- </Dropdown>
- ) : (
- <Button color="primary" outline onClick={props.onMember}>
- {t('timeline.memberButton')}
- </Button>
- )}
- </div>
- </div>
- );
-};
-
-export default UserInfoCard;
diff --git a/Timeline/ClientApp/src/app/user/UserPage.tsx b/Timeline/ClientApp/src/app/user/UserPage.tsx
deleted file mode 100644
index 98fd06f8..00000000
--- a/Timeline/ClientApp/src/app/user/UserPage.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-
-import { ExcludeKey } from '../type-utilities';
-import { TimelineInfo } from '../data/timeline';
-
-import TimelinePageTemplateUI, {
- TimelinePageTemplateUIProps
-} from '../timeline/TimelinePageTemplateUI';
-import UserInfoCard, { PersonalTimelineManageItem } from './UserInfoCard';
-
-export type UserPageProps = ExcludeKey<
- TimelinePageTemplateUIProps<TimelineInfo, PersonalTimelineManageItem>,
- 'CardComponent'
->;
-
-const UserPage: React.FC<UserPageProps> = props => {
- return <TimelinePageTemplateUI {...props} CardComponent={UserInfoCard} />;
-};
-
-export default UserPage;
diff --git a/Timeline/ClientApp/src/app/user/api.ts b/Timeline/ClientApp/src/app/user/api.ts
deleted file mode 100644
index a9855eb0..00000000
--- a/Timeline/ClientApp/src/app/user/api.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import axios from 'axios';
-import { BehaviorSubject, Observable } from 'rxjs';
-
-import { apiBaseUrl } from '../config';
-import { User } from '../data/user';
-import { updateQueryString } from '../helper';
-
-export function changeNickname(
- token: string,
- username: string,
- newNickname: string
-): Promise<User> {
- return axios
- .patch<User>(`${apiBaseUrl}/users/${username}?token=${token}`, {
- nickname: newNickname,
- })
- .then((res) => res.data);
-}
-
-const avatarVersionSubject = new BehaviorSubject<number | undefined>(undefined);
-
-export function changeAvatar(
- token: string,
- username: string,
- data: Blob,
- type: string
-): Promise<void> {
- return axios
- .put(`${apiBaseUrl}/users/${username}/avatar?token=${token}`, data, {
- headers: {
- 'Content-Type': type,
- },
- })
- .then(() => {
- avatarVersionSubject.next((avatarVersionSubject.value ?? 0) + 1);
- });
-}
-
-export const avatarVersion$: Observable<
- number | undefined
-> = avatarVersionSubject;
-
-export function useAvatarVersion(): number | undefined {
- const [version, setVersion] = React.useState<number | undefined>();
- React.useEffect(() => {
- const subscription = avatarVersion$.subscribe((v) => setVersion(v));
- return () => subscription.unsubscribe();
- }, []);
- return version;
-}
-
-export function useOptionalVersionedAvatarUrl(
- url: string | undefined
-): string | undefined {
- const avatarVersion = useAvatarVersion();
- return React.useMemo(
- () =>
- url == null
- ? undefined
- : updateQueryString(
- 'v',
- avatarVersion == null ? null : avatarVersion.toString(),
- url
- ),
- [avatarVersion, url]
- );
-}
-
-export function useAvatarUrlWithGivenVersion(
- version: number | null | undefined,
- url: string
-): string {
- return React.useMemo(
- () =>
- updateQueryString('v', version == null ? null : version.toString(), url),
- [version, url]
- );
-}
diff --git a/Timeline/ClientApp/src/app/user/user-page.sass b/Timeline/ClientApp/src/app/user/user-page.sass
deleted file mode 100644
index fe3ab70b..00000000
--- a/Timeline/ClientApp/src/app/user/user-page.sass
+++ /dev/null
@@ -1,11 +0,0 @@
-.login-container
- max-width: 600px
-
-.change-avatar-cropper-row
- max-height: 400px
-
-.change-avatar-img
- min-width: 50%
- max-width: 100%
- max-height: 400px
-