1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

fixed cyclic dependencies for dialogs

This commit is contained in:
Fedor Katurov 2019-11-25 15:02:32 +07:00
parent d7ed0cbe54
commit c0c832d158
19 changed files with 399 additions and 263 deletions

127
package-lock.json generated
View file

@ -3052,6 +3052,7 @@
"version": "2.10.1", "version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"optional": true,
"requires": { "requires": {
"hoek": "2.x.x" "hoek": "2.x.x"
} }
@ -3419,6 +3420,12 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"circular-dependency-plugin": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz",
"integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==",
"dev": true
},
"clap": { "clap": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
@ -3493,6 +3500,10 @@
} }
} }
}, },
"classie": {
"version": "github:eiriklv/classie#da1d3019904433872a8656d3cd69fc41d69c477a",
"from": "github:eiriklv/classie"
},
"classnames": { "classnames": {
"version": "2.2.6", "version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
@ -4963,6 +4974,10 @@
"minimalistic-assert": "^1.0.0" "minimalistic-assert": "^1.0.0"
} }
}, },
"desandro-get-style-property": {
"version": "github:eiriklv/get-style-property#a5a74ad48d96c7d5ddcf652e9fa5d4283af37823",
"from": "github:eiriklv/get-style-property"
},
"destroy": { "destroy": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@ -5030,6 +5045,19 @@
"buffer-indexof": "^1.0.0" "buffer-indexof": "^1.0.0"
} }
}, },
"doc-ready": {
"version": "github:eiriklv/doc-ready#31c2481101af5dab33311fea4c7fc684b58fa8ad",
"from": "github:eiriklv/doc-ready",
"requires": {
"eventie": "github:eiriklv/eventie"
},
"dependencies": {
"eventie": {
"version": "github:eiriklv/eventie#c9d290c6aa57712257dc8c0b6bf21c9374190a3c",
"from": "github:eiriklv/eventie"
}
}
},
"doctrine": { "doctrine": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@ -5706,12 +5734,21 @@
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"dev": true "dev": true
}, },
"eventemitter": {
"version": "github:braznaavtrav/EventEmitter#7169056a2f8b3b55d78ab1b85bad39277e7e88b2",
"from": "github:braznaavtrav/EventEmitter"
},
"eventemitter3": { "eventemitter3": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
"integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
"dev": true "dev": true
}, },
"eventie": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/eventie/-/eventie-1.0.6.tgz",
"integrity": "sha1-1P/IsMK15JPCqhsiy+kY067nRDc="
},
"events": { "events": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
@ -6294,7 +6331,8 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -6709,7 +6747,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -6765,6 +6804,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -6808,12 +6848,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },
@ -6899,6 +6941,13 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
}, },
"get-size": {
"version": "github:eiriklv/get-size#c1ebd019815fc6247c094c17a41b61d0e8191b08",
"from": "github:eiriklv/get-size",
"requires": {
"desandro-get-style-property": "github:eiriklv/get-style-property"
}
},
"get-stdin": { "get-stdin": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
@ -7233,7 +7282,8 @@
"hoek": { "hoek": {
"version": "2.16.3", "version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
"optional": true
}, },
"hoist-non-react-statics": { "hoist-non-react-statics": {
"version": "3.3.0", "version": "3.3.0",
@ -7541,6 +7591,14 @@
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
"optional": true "optional": true
}, },
"imagesloaded": {
"version": "github:eiriklv/imagesloaded#04535a148206e58790927e133f24ca199163b995",
"from": "github:eiriklv/imagesloaded",
"requires": {
"eventie": ">=1.0.4 <2",
"wolfy87-eventemitter": "4.x"
}
},
"immutable": { "immutable": {
"version": "3.8.2", "version": "3.8.2",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz",
@ -8644,6 +8702,10 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"matches-selector": {
"version": "github:desandro/matches-selector#082376f4bbe7ff8c5c6bb258ec43259c9a80a7c3",
"from": "github:desandro/matches-selector#v1.0.3"
},
"math-expression-evaluator": { "math-expression-evaluator": {
"version": "1.2.17", "version": "1.2.17",
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
@ -9614,6 +9676,24 @@
"os-tmpdir": "^1.0.0" "os-tmpdir": "^1.0.0"
} }
}, },
"outlayer": {
"version": "github:eiriklv/outlayer#aea1c8239d30ccc1d3664ca3fff2f6d4b20fb812",
"from": "github:eiriklv/outlayer",
"requires": {
"desandro-get-style-property": "github:eiriklv/get-style-property",
"doc-ready": "github:eiriklv/doc-ready",
"eventemitter": "github:braznaavtrav/EventEmitter",
"eventie": "github:eiriklv/eventie",
"get-size": "github:eiriklv/get-size",
"matches-selector": "github:desandro/matches-selector#v1.0.3"
},
"dependencies": {
"eventie": {
"version": "github:eiriklv/eventie#c9d290c6aa57712257dc8c0b6bf21c9374190a3c",
"from": "github:eiriklv/eventie"
}
}
},
"output-file-sync": { "output-file-sync": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz",
@ -9679,6 +9759,16 @@
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
}, },
"packery": {
"version": "github:eiriklv/packery#8e812a0a16575ef923f5e72efcea85aadc6fea67",
"from": "github:eiriklv/packery",
"requires": {
"classie": "github:eiriklv/classie",
"desandro-get-style-property": "github:eiriklv/get-style-property",
"get-size": "github:eiriklv/get-size",
"outlayer": "github:eiriklv/outlayer"
}
},
"pako": { "pako": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
@ -10993,25 +11083,9 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/react-packery-component/-/react-packery-component-1.0.2.tgz", "resolved": "https://registry.npmjs.org/react-packery-component/-/react-packery-component-1.0.2.tgz",
"integrity": "sha1-FSEiHaSRZ8s87fR9W1UsM0iBgKk=", "integrity": "sha1-FSEiHaSRZ8s87fR9W1UsM0iBgKk=",
"dependencies": { "requires": {
"imagesloaded": { "imagesloaded": "github:eiriklv/imagesloaded",
"version": "github:eiriklv/imagesloaded#04535a148206e58790927e133f24ca199163b995", "packery": "github:eiriklv/packery"
"from": "github:eiriklv/imagesloaded#04535a148206e58790927e133f24ca199163b995",
"requires": {
"eventie": ">=1.0.4 <2",
"wolfy87-eventemitter": "4.x"
}
},
"packery": {
"version": "github:eiriklv/packery#8e812a0a16575ef923f5e72efcea85aadc6fea67",
"from": "github:eiriklv/packery#8e812a0a16575ef923f5e72efcea85aadc6fea67",
"requires": {
"classie": "github:eiriklv/classie#da1d3019904433872a8656d3cd69fc41d69c477a",
"desandro-get-style-property": "github:eiriklv/get-style-property#a5a74ad48d96c7d5ddcf652e9fa5d4283af37823",
"get-size": "github:eiriklv/get-size#c1ebd019815fc6247c094c17a41b61d0e8191b08",
"outlayer": "github:eiriklv/outlayer#aea1c8239d30ccc1d3664ca3fff2f6d4b20fb812"
}
}
} }
}, },
"react-redux": { "react-redux": {
@ -14433,6 +14507,11 @@
"string-width": "^1.0.2 || 2" "string-width": "^1.0.2 || 2"
} }
}, },
"wolfy87-eventemitter": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-4.3.0.tgz",
"integrity": "sha1-ZJc5bJXnQ1nwa241QJM5MY2Nlk8="
},
"wordwrap": { "wordwrap": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",

View file

@ -28,6 +28,7 @@
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1", "babel-preset-stage-2": "^6.24.1",
"circular-dependency-plugin": "^5.2.0",
"css-loader": "^0.28.11", "css-loader": "^0.28.11",
"file-loader": "^1.1.11", "file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",

View file

@ -4,8 +4,9 @@ import { connect } from 'react-redux';
import { UPLOAD_TYPES } from '~/redux/uploads/constants'; import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { ImageGrid } from '../ImageGrid'; import { ImageGrid } from '../ImageGrid';
import { AudioGrid } from '../AudioGrid'; import { AudioGrid } from '../AudioGrid';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors'; import { selectUploads } from '~/redux/uploads/selectors';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
const mapStateToProps = selectUploads; const mapStateToProps = selectUploads;

View file

@ -1,11 +1,12 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import { SortEnd } from 'react-sortable-hoc'; import { SortEnd } from 'react-sortable-hoc';
import * as styles from './styles.scss';
import { IFile } from '~/redux/types'; import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';
import { moveArrItem } from '~/utils/fn'; import { moveArrItem } from '~/utils/fn';
import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid'; import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid';
import * as styles from './styles.scss';
interface IProps { interface IProps {
files: IFile[]; files: IFile[];
setFiles: (val: IFile[]) => void; setFiles: (val: IFile[]) => void;

30
src/constants/dialogs.ts Normal file
View file

@ -0,0 +1,30 @@
import { NODE_TYPES } from '~/redux/node/constants';
import { EditorDialogImage } from '~/containers/editors/EditorDialogImage';
import { EditorDialogText } from '~/containers/editors/EditorDialogText';
import { EditorDialogVideo } from '~/containers/editors/EditorDialogVideo';
import { EditorDialogAudio } from '~/containers/editors/EditorDialogAudio';
import { LoginDialog } from '~/containers/dialogs/LoginDialog';
import { LoadingDialog } from '~/containers/dialogs/LoadingDialog';
import { TestDialog } from '~/containers/dialogs/TestDialog';
import { ProfileDialog } from '~/containers/dialogs/ProfileDialog';
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
import { DIALOGS } from '~/redux/modal/constants';
export const DIALOG_CONTENT = {
[DIALOGS.EDITOR_IMAGE]: EditorDialogImage,
[DIALOGS.EDITOR_TEXT]: EditorDialogText,
[DIALOGS.EDITOR_VIDEO]: EditorDialogVideo,
[DIALOGS.EDITOR_AUDIO]: EditorDialogAudio,
[DIALOGS.LOGIN]: LoginDialog,
[DIALOGS.LOADING]: LoadingDialog,
[DIALOGS.TEST]: TestDialog,
[DIALOGS.PROFILE]: ProfileDialog,
[DIALOGS.RESTORE_REQUEST]: RestoreRequestDialog,
};
export const NODE_EDITOR_DIALOGS = {
[NODE_TYPES.IMAGE]: DIALOGS.EDITOR_IMAGE,
[NODE_TYPES.TEXT]: DIALOGS.EDITOR_TEXT,
[NODE_TYPES.VIDEO]: DIALOGS.EDITOR_VIDEO,
[NODE_TYPES.AUDIO]: DIALOGS.EDITOR_AUDIO,
};

View file

@ -1,35 +1,37 @@
export const ERRORS = { export const ERRORS = {
NOT_AN_EMAIL: "Not_An_Email", NOT_AN_EMAIL: 'Not_An_Email',
TOO_SHIRT: "Is_Too_Shirt", TOO_SHIRT: 'Is_Too_Shirt',
EMPTY_RESPONSE: "Empty_Response", EMPTY_RESPONSE: 'Empty_Response',
NO_COMMENTS: "No_Comments", NO_COMMENTS: 'No_Comments',
FILES_REQUIRED: "Files_Required", FILES_REQUIRED: 'Files_Required',
TEXT_REQUIRED: "Text_Required", TEXT_REQUIRED: 'Text_Required',
UNKNOWN_NODE_TYPE: "Unknown_Node_Type", UNKNOWN_NODE_TYPE: 'Unknown_Node_Type',
URL_INVALID: "Url_Invalid", URL_INVALID: 'Url_Invalid',
FILES_AUDIO_REQUIRED: "Files_Audio_Required", FILES_AUDIO_REQUIRED: 'Files_Audio_Required',
NOT_ENOUGH_RIGHTS: "Not_Enough_Rights", NOT_ENOUGH_RIGHTS: 'Not_Enough_Rights',
INCORRECT_DATA: "Incorrect_Data", INCORRECT_DATA: 'Incorrect_Data',
IMAGE_CONVERSION_FAILED: "Image_Conversion_Failed", IMAGE_CONVERSION_FAILED: 'Image_Conversion_Failed',
USER_NOT_FOUND: "User_Not_found", USER_NOT_FOUND: 'User_Not_found',
USER_EXIST: "User_Exist", USER_EXIST: 'User_Exist',
INCORRECT_PASSWORD: "Incorrect_Password" INCORRECT_PASSWORD: 'Incorrect_Password',
CODE_IS_INVALID: 'Code_Is_Invalid',
}; };
export const ERROR_LITERAL = { export const ERROR_LITERAL = {
[ERRORS.NOT_AN_EMAIL]: "Введите правильный e-mail", [ERRORS.NOT_AN_EMAIL]: 'Введите правильный e-mail',
[ERRORS.TOO_SHIRT]: "Слишком короткий", [ERRORS.TOO_SHIRT]: 'Слишком короткий',
[ERRORS.NO_COMMENTS]: "Комментариев пока нет", [ERRORS.NO_COMMENTS]: 'Комментариев пока нет',
[ERRORS.EMPTY_RESPONSE]: "Пустой ответ сервера", [ERRORS.EMPTY_RESPONSE]: 'Пустой ответ сервера',
[ERRORS.FILES_REQUIRED]: "Добавьте файлы", [ERRORS.FILES_REQUIRED]: 'Добавьте файлы',
[ERRORS.TEXT_REQUIRED]: "Нужно немного текста", [ERRORS.TEXT_REQUIRED]: 'Нужно немного текста',
[ERRORS.UNKNOWN_NODE_TYPE]: "Неизвестный тип поста", [ERRORS.UNKNOWN_NODE_TYPE]: 'Неизвестный тип поста',
[ERRORS.URL_INVALID]: "Неизвестный адрес", [ERRORS.URL_INVALID]: 'Неизвестный адрес',
[ERRORS.FILES_AUDIO_REQUIRED]: "Нужна хотя бы одна песня", [ERRORS.FILES_AUDIO_REQUIRED]: 'Нужна хотя бы одна песня',
[ERRORS.NOT_ENOUGH_RIGHTS]: "У вас недостаточно прав", [ERRORS.NOT_ENOUGH_RIGHTS]: 'У вас недостаточно прав',
[ERRORS.INCORRECT_DATA]: "Недопустимые данные", [ERRORS.INCORRECT_DATA]: 'Недопустимые данные',
[ERRORS.IMAGE_CONVERSION_FAILED]: "Не удалось изменить изображение", [ERRORS.IMAGE_CONVERSION_FAILED]: 'Не удалось изменить изображение',
[ERRORS.USER_NOT_FOUND]: "Пользователь не найден", [ERRORS.USER_NOT_FOUND]: 'Пользователь не найден',
[ERRORS.USER_EXIST]: "Такой пользователь уже существует", [ERRORS.USER_EXIST]: 'Такой пользователь уже существует',
[ERRORS.INCORRECT_PASSWORD]: "Неправильный пароль" [ERRORS.INCORRECT_PASSWORD]: 'Неправильный пароль',
[ERRORS.CODE_IS_INVALID]: 'Код не существует или устарел',
}; };

View file

@ -1,37 +1,43 @@
import React, { FC, FormEvent, useCallback, useEffect, useState } from "react"; import React, { FC, FormEvent, useCallback, useEffect, useState, useMemo } from 'react';
import { connect } from "react-redux"; import { connect } from 'react-redux';
import { ScrollDialog } from "../ScrollDialog"; import { IDialogProps } from '~/redux/modal/constants';
import { IDialogProps } from "~/redux/modal/constants"; import { DIALOGS } from '~/redux/modal/constants';
import { useCloseOnEscape } from "~/utils/hooks"; import { useCloseOnEscape } from '~/utils/hooks';
import { Group } from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
import { InputText } from "~/components/input/InputText"; import { InputText } from '~/components/input/InputText';
import { Button } from "~/components/input/Button"; import { Button } from '~/components/input/Button';
import { Padder } from "~/components/containers/Padder"; import { Padder } from '~/components/containers/Padder';
import * as styles from "./styles.scss"; import { selectAuthLogin } from '~/redux/auth/selectors';
import { selectAuthLogin } from "~/redux/auth/selectors"; import { API } from '~/constants/api';
import * as ACTIONS from "~/redux/auth/actions"; import { BetterScrollDialog } from '../BetterScrollDialog';
import { API } from "~/constants/api";
import { BetterScrollDialog } from "../BetterScrollDialog"; import * as styles from './styles.scss';
import * as ACTIONS from '~/redux/auth/actions';
import * as MODAL_ACTIONS from '~/redux/modal/actions';
const mapStateToProps = selectAuthLogin; const mapStateToProps = selectAuthLogin;
const mapDispatchToProps = { const mapDispatchToProps = {
userSendLoginRequest: ACTIONS.userSendLoginRequest, userSendLoginRequest: ACTIONS.userSendLoginRequest,
userSetLoginError: ACTIONS.userSetLoginError userSetLoginError: ACTIONS.userSetLoginError,
modalShowDialog: MODAL_ACTIONS.modalShowDialog,
}; };
type IProps = ReturnType<typeof mapStateToProps> & type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & IDialogProps & {};
typeof mapDispatchToProps &
IDialogProps & {}; console.log('initial', MODAL_ACTIONS);
const LoginDialogUnconnected: FC<IProps> = ({ const LoginDialogUnconnected: FC<IProps> = ({
onRequestClose, onRequestClose,
error, error,
userSendLoginRequest, userSendLoginRequest,
userSetLoginError userSetLoginError,
modalShowDialog,
}) => { }) => {
const [username, setUserName] = useState(""); console.log({ modalShowDialog, MODAL_ACTIONS });
const [password, setPassword] = useState("");
const [username, setUserName] = useState('');
const [password, setPassword] = useState('');
const onSubmit = useCallback( const onSubmit = useCallback(
(event: FormEvent) => { (event: FormEvent) => {
@ -41,61 +47,60 @@ const LoginDialogUnconnected: FC<IProps> = ({
[userSendLoginRequest, username, password] [userSendLoginRequest, username, password]
); );
const onRestoreRequest = useCallback(
event => {
console.log('a', { MODAL_ACTIONS, modalShowDialog, userSetLoginError });
event.preventDefault();
modalShowDialog(DIALOGS.RESTORE_REQUEST);
},
[modalShowDialog, userSetLoginError]
);
const onSocialLogin = useCallback(() => { const onSocialLogin = useCallback(() => {
window.open(API.USER.VKONTAKTE_LOGIN, "", "width=600,height=400"); window.open(API.USER.VKONTAKTE_LOGIN, '', 'width=600,height=400');
}, []); }, []);
useEffect(() => { useEffect(() => {
if (error) userSetLoginError(null); if (error) userSetLoginError(null);
}, [username, password]); }, [username, password]);
const buttons = ( const buttons = useMemo(
<Group horizontal className={styles.footer}> () => (
<Button stretchy> <Group className={styles.footer}>
<span>Войти</span> <Button
</Button> className={styles.secondary_button}
</Group> iconLeft="vk"
type="button"
onClick={onSocialLogin}
>
<span>Вконтакте</span>
</Button>
<Button>
<span>Войти</span>
</Button>
</Group>
),
[onSocialLogin]
); );
useCloseOnEscape(onRequestClose); useCloseOnEscape(onRequestClose);
return ( return (
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<BetterScrollDialog <BetterScrollDialog width={260} error={error} onClose={onRequestClose} footer={buttons}>
width={260}
error={error}
onClose={onRequestClose}
footer={buttons}
>
<Padder> <Padder>
<div className={styles.wrap}> <div className={styles.wrap}>
<Group> <Group>
<h2>РЕШИТЕЛЬНО ВОЙТИ</h2> <h2>РЕШИТЕЛЬНО ВОЙТИ</h2>
<InputText <InputText title="Логин" handler={setUserName} value={username} autoFocus />
title="Логин"
handler={setUserName}
value={username}
autoFocus
/>
<InputText <InputText title="Пароль" handler={setPassword} value={password} type="password" />
title="Пароль"
handler={setPassword}
value={password}
type="password"
/>
<Group className={styles.buttons}> <Button className={styles.forgot_button} type="button" onClick={onRestoreRequest}>
<Button Вспомнить пароль
className={styles.vk} </Button>
iconLeft="vk"
type="button"
onClick={onSocialLogin}
>
<span>Вконтакте</span>
</Button>
</Group>
</Group> </Group>
</div> </div>
</Padder> </Padder>

View file

@ -1,4 +1,5 @@
$vk_color: darken(desaturate($blue, 100%), 30%); $secondary_color: darken(desaturate($blue, 100%), 30%);
$vk_color: $secondary_color;
.wrap { .wrap {
display: flex; display: flex;
@ -15,7 +16,7 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
} }
} }
.vk { .secondary_button {
background: $content_bg; background: $content_bg;
box-shadow: inset $vk_color 0 0 0 2px; box-shadow: inset $vk_color 0 0 0 2px;
color: $vk_color; color: $vk_color;
@ -23,11 +24,15 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
svg { svg {
fill: $vk_color; fill: $vk_color;
margin-right: $gap; margin-right: $gap;
// width: 24px;
// height: 24px;
} }
} }
.forgot_button {
background: $content_bg;
box-shadow: none;
color: $secondary_color;
}
.buttons { .buttons {
margin: $gap * 2 0 0 0 !important; margin: $gap * 2 0 0 0 !important;
padding: $gap * 2 0 0 0; padding: $gap * 2 0 0 0;
@ -41,3 +46,12 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
// text-align: left; // text-align: left;
} }
} }
.links {
font: $font_14_regular;
text-align: center;
a {
color: lighten($content_bg, 40%);
}
}

View file

@ -4,7 +4,7 @@ import ReactDOM from 'react-dom';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { IState } from '~/redux/store'; import { IState } from '~/redux/store';
import * as ACTIONS from '~/redux/modal/actions'; import * as ACTIONS from '~/redux/modal/actions';
import { DIALOG_CONTENT } from '~/redux/modal/constants'; import { DIALOG_CONTENT } from '~/constants/dialogs';
const mapStateToProps = ({ modal }: IState) => ({ ...modal }); const mapStateToProps = ({ modal }: IState) => ({ ...modal });
const mapDispatchToProps = { const mapDispatchToProps = {

View file

@ -0,0 +1,41 @@
import React, { FC, useState, useMemo, useCallback } from 'react';
import { IDialogProps } from '~/redux/types';
import { connect } from 'react-redux';
import { BetterScrollDialog } from '../BetterScrollDialog';
import { Group } from '~/components/containers/Group';
import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button';
const mapStateToProps = () => ({});
const mapDispatchToProps = {};
type IProps = IDialogProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const RestoreRequestDialogUnconnected: FC<IProps> = ({}) => {
const [field, setField] = useState();
const onSubmit = useCallback(event => {
event.preventDefault();
}, []);
const buttons = useMemo(() => <Button>Восстановить</Button>, []);
return (
<form onSubmit={onSubmit}>
<BetterScrollDialog footer={buttons}>
<Group>
<InputText title="Имя или email" value={field} handler={setField} />
<div>Введите имя пользователя или адрес почты. Мы пришлем ссылку для сброса пароля.</div>
</Group>
</BetterScrollDialog>
</form>
);
};
const RestoreRequestDialog = connect(
mapStateToProps,
mapDispatchToProps
)(RestoreRequestDialogUnconnected);
export { RestoreRequestDialog };

View file

@ -34,6 +34,7 @@ const INITIAL_STATE: IAuthState = {
restore: { restore: {
code: '', code: '',
user: null,
is_loading: false, is_loading: false,
is_succesfull: false, is_succesfull: false,
errors: {}, errors: {},

View file

@ -1,17 +1,5 @@
import { import { call, put, takeEvery, takeLatest, select, delay } from 'redux-saga/effects';
call, import { AUTH_USER_ACTIONS, EMPTY_USER, USER_ERRORS, USER_ROLES } from '~/redux/auth/constants';
put,
takeEvery,
takeLatest,
select,
delay
} from "redux-saga/effects";
import {
AUTH_USER_ACTIONS,
EMPTY_USER,
USER_ERRORS,
USER_ROLES
} from "~/redux/auth/constants";
import { import {
authSetToken, authSetToken,
userSetLoginError, userSetLoginError,
@ -25,8 +13,10 @@ import {
authSetUpdates, authSetUpdates,
authLoggedIn, authLoggedIn,
authSetLastSeenMessages, authSetLastSeenMessages,
authPatchUser authPatchUser,
} from "~/redux/auth/actions"; authRestorePassword,
authSetRestore,
} from '~/redux/auth/actions';
import { import {
apiUserLogin, apiUserLogin,
apiAuthGetUser, apiAuthGetUser,
@ -34,31 +24,19 @@ import {
apiAuthGetUserMessages, apiAuthGetUserMessages,
apiAuthSendMessage, apiAuthSendMessage,
apiAuthGetUpdates, apiAuthGetUpdates,
apiUpdateUser apiUpdateUser,
} from "~/redux/auth/api"; } from '~/redux/auth/api';
import { modalSetShown, modalShowDialog } from "~/redux/modal/actions"; import { modalSetShown, modalShowDialog } from '~/redux/modal/actions';
import { import { selectToken, selectAuthProfile, selectAuthUser, selectAuthUpdates } from './selectors';
selectToken, import { IResultWithStatus, INotification, IMessageNotification } from '../types';
selectAuthProfile, import { IUser, IAuthState } from './types';
selectAuthUser, import { REHYDRATE, RehydrateAction } from 'redux-persist';
selectAuthUpdates import { selectModal } from '~/redux/modal/selectors';
} from "./selectors"; import { IModalState } from '~/redux/modal/reducer';
import { import { DIALOGS } from '~/redux/modal/constants';
IResultWithStatus, import { ERRORS } from '~/constants/errors';
INotification,
IMessageNotification
} from "../types";
import { IUser, IAuthState } from "./types";
import { REHYDRATE, RehydrateAction } from "redux-persist";
import { selectModal } from "../modal/selectors";
import { IModalState } from "../modal/reducer";
import { DIALOGS } from "../modal/constants";
import { ERRORS } from "~/constants/errors";
export function* reqWrapper( export function* reqWrapper(requestAction, props = {}): ReturnType<typeof requestAction> {
requestAction,
props = {}
): ReturnType<typeof requestAction> {
const access = yield select(selectToken); const access = yield select(selectToken);
const result = yield call(requestAction, { access, ...props }); const result = yield call(requestAction, { access, ...props });
@ -70,22 +48,16 @@ export function* reqWrapper(
return result; return result;
} }
function* sendLoginRequestSaga({ function* sendLoginRequestSaga({ username, password }: ReturnType<typeof userSendLoginRequest>) {
username,
password
}: ReturnType<typeof userSendLoginRequest>) {
if (!username || !password) return; if (!username || !password) return;
const { const {
error, error,
data: { token, user } data: { token, user },
}: IResultWithStatus<{ token: string; user: IUser }> = yield call( }: IResultWithStatus<{ token: string; user: IUser }> = yield call(apiUserLogin, {
apiUserLogin, username,
{ password,
username, });
password
}
);
if (error) { if (error) {
yield put(userSetLoginError(error)); yield put(userSetLoginError(error));
@ -101,17 +73,14 @@ function* sendLoginRequestSaga({
function* refreshUser() { function* refreshUser() {
const { const {
error, error,
data: { user } data: { user },
}: IResultWithStatus<{ user: IUser }> = yield call( }: IResultWithStatus<{ user: IUser }> = yield call(reqWrapper, apiAuthGetUser);
reqWrapper,
apiAuthGetUser
);
if (error) { if (error) {
yield put( yield put(
authSetUser({ authSetUser({
...EMPTY_USER, ...EMPTY_USER,
is_user: false is_user: false,
}) })
); );
@ -122,7 +91,7 @@ function* refreshUser() {
} }
function* checkUserSaga({ key }: RehydrateAction) { function* checkUserSaga({ key }: RehydrateAction) {
if (key !== "auth") return; if (key !== 'auth') return;
yield call(refreshUser); yield call(refreshUser);
// yield put(authOpenProfile("gvorcek", "settings")); // yield put(authOpenProfile("gvorcek", "settings"));
} }
@ -142,21 +111,18 @@ function* logoutSaga() {
yield put( yield put(
authSetUpdates({ authSetUpdates({
last: null, last: null,
notifications: [] notifications: [],
}) })
); );
} }
function* openProfile({ function* openProfile({ username, tab = 'profile' }: ReturnType<typeof authOpenProfile>) {
username,
tab = "profile"
}: ReturnType<typeof authOpenProfile>) {
yield put(modalShowDialog(DIALOGS.PROFILE)); yield put(modalShowDialog(DIALOGS.PROFILE));
yield put(authSetProfile({ is_loading: true, tab })); yield put(authSetProfile({ is_loading: true, tab }));
const { const {
error, error,
data: { user } data: { user },
} = yield call(reqWrapper, apiAuthGetUserProfile, { username }); } = yield call(reqWrapper, apiAuthGetUserProfile, { username });
if (error || !user) { if (error || !user) {
@ -176,16 +142,15 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
messages: messages:
messages && messages &&
messages.length > 0 && messages.length > 0 &&
(messages[0].to.username === username || (messages[0].to.username === username || messages[0].from.username === username)
messages[0].from.username === username)
? messages ? messages
: [] : [],
}) })
); );
const { const {
error, error,
data data,
// data: { messages }, // data: { messages },
} = yield call(reqWrapper, apiAuthGetUserMessages, { username }); } = yield call(reqWrapper, apiAuthGetUserMessages, { username });
@ -193,21 +158,19 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
return yield put( return yield put(
authSetProfile({ authSetProfile({
is_loading_messages: false, is_loading_messages: false,
messages_error: ERRORS.EMPTY_RESPONSE messages_error: ERRORS.EMPTY_RESPONSE,
}) })
); );
} }
yield put( yield put(authSetProfile({ is_loading_messages: false, messages: data.messages }));
authSetProfile({ is_loading_messages: false, messages: data.messages })
);
const { notifications } = yield select(selectAuthUpdates); const { notifications } = yield select(selectAuthUpdates);
// clear viewed message from notifcation list // clear viewed message from notifcation list
const filtered = notifications.filter( const filtered = notifications.filter(
notification => notification =>
notification.type !== "message" || notification.type !== 'message' ||
(notification as IMessageNotification).content.from.username !== username (notification as IMessageNotification).content.from.username !== username
); );
@ -216,23 +179,18 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
} }
} }
function* sendMessage({ function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>) {
message,
onSuccess
}: ReturnType<typeof authSendMessage>) {
const { const {
user: { username } user: { username },
} = yield select(selectAuthProfile); } = yield select(selectAuthProfile);
if (!username) return; if (!username) return;
yield put( yield put(authSetProfile({ is_sending_messages: true, messages_error: null }));
authSetProfile({ is_sending_messages: true, messages_error: null })
);
const { error, data } = yield call(reqWrapper, apiAuthSendMessage, { const { error, data } = yield call(reqWrapper, apiAuthSendMessage, {
username, username,
message message,
}); });
console.log({ error, data }); console.log({ error, data });
@ -241,7 +199,7 @@ function* sendMessage({
return yield put( return yield put(
authSetProfile({ authSetProfile({
is_sending_messages: false, is_sending_messages: false,
messages_error: error || ERRORS.EMPTY_RESPONSE messages_error: error || ERRORS.EMPTY_RESPONSE,
}) })
); );
} }
@ -255,7 +213,7 @@ function* sendMessage({
yield put( yield put(
authSetProfile({ authSetProfile({
is_sending_messages: false, is_sending_messages: false,
messages: [data.message, ...messages] messages: [data.message, ...messages],
}) })
); );
@ -265,35 +223,28 @@ function* sendMessage({
function* getUpdates() { function* getUpdates() {
const user = yield select(selectAuthUser); const user = yield select(selectAuthUser);
if (!user || !user.is_user || user.role === USER_ROLES.GUEST || !user.id) if (!user || !user.is_user || user.role === USER_ROLES.GUEST || !user.id) return;
return;
const modal: IModalState = yield select(selectModal); const modal: IModalState = yield select(selectModal);
const profile: IAuthState["profile"] = yield select(selectAuthProfile); const profile: IAuthState['profile'] = yield select(selectAuthProfile);
const { last }: IAuthState["updates"] = yield select(selectAuthUpdates); const { last }: IAuthState['updates'] = yield select(selectAuthUpdates);
const exclude_dialogs = const exclude_dialogs =
modal.is_shown && modal.dialog === DIALOGS.PROFILE && profile.user.id modal.is_shown && modal.dialog === DIALOGS.PROFILE && profile.user.id ? profile.user.id : null;
? profile.user.id
: null;
const { const { error, data }: IResultWithStatus<{ notifications: INotification[] }> = yield call(
error,
data
}: IResultWithStatus<{ notifications: INotification[] }> = yield call(
reqWrapper, reqWrapper,
apiAuthGetUpdates, apiAuthGetUpdates,
{ exclude_dialogs, last: last || user.last_seen_messages } { exclude_dialogs, last: last || user.last_seen_messages }
); );
if (error || !data || !data.notifications || !data.notifications.length) if (error || !data || !data.notifications || !data.notifications.length) return;
return;
const { notifications } = data; const { notifications } = data;
yield put( yield put(
authSetUpdates({ authSetUpdates({
last: notifications[0].created_at, last: notifications[0].created_at,
notifications notifications,
}) })
); );
} }
@ -305,9 +256,7 @@ function* startPollingSaga() {
} }
} }
function* setLastSeenMessages({ function* setLastSeenMessages({ last_seen_messages }: ReturnType<typeof authSetLastSeenMessages>) {
last_seen_messages
}: ReturnType<typeof authSetLastSeenMessages>) {
if (!Date.parse(last_seen_messages)) return; if (!Date.parse(last_seen_messages)) return;
yield call(reqWrapper, apiUpdateUser, { user: { last_seen_messages } }); yield call(reqWrapper, apiUpdateUser, { user: { last_seen_messages } });
@ -323,7 +272,19 @@ function* patchUser({ user }: ReturnType<typeof authPatchUser>) {
} }
yield put(authSetUser({ ...me, ...data.user })); yield put(authSetUser({ ...me, ...data.user }));
yield put(authSetProfile({ user: { ...me, ...data.user }, tab: "profile" })); yield put(authSetProfile({ user: { ...me, ...data.user }, tab: 'profile' }));
}
function* restorePassword({ code }: ReturnType<typeof authRestorePassword>) {
if (!code && !code.length) {
return yield put(
authSetRestore({
errors: { code: ERRORS.CODE_IS_INVALID },
is_loading: false,
})
);
}
console.log({ code });
} }
function* authSaga() { function* authSaga() {
@ -336,11 +297,9 @@ function* authSaga() {
yield takeLatest(AUTH_USER_ACTIONS.OPEN_PROFILE, openProfile); yield takeLatest(AUTH_USER_ACTIONS.OPEN_PROFILE, openProfile);
yield takeLatest(AUTH_USER_ACTIONS.GET_MESSAGES, getMessages); yield takeLatest(AUTH_USER_ACTIONS.GET_MESSAGES, getMessages);
yield takeLatest(AUTH_USER_ACTIONS.SEND_MESSAGE, sendMessage); yield takeLatest(AUTH_USER_ACTIONS.SEND_MESSAGE, sendMessage);
yield takeLatest( yield takeLatest(AUTH_USER_ACTIONS.SET_LAST_SEEN_MESSAGES, setLastSeenMessages);
AUTH_USER_ACTIONS.SET_LAST_SEEN_MESSAGES,
setLastSeenMessages
);
yield takeLatest(AUTH_USER_ACTIONS.PATCH_USER, patchUser); yield takeLatest(AUTH_USER_ACTIONS.PATCH_USER, patchUser);
yield takeLatest(AUTH_USER_ACTIONS.RESTORE_PASSWORD, restorePassword);
} }
export default authSaga; export default authSaga;

View file

@ -52,6 +52,7 @@ export type IAuthState = Readonly<{
restore: { restore: {
code: string; code: string;
user: Pick<IUser, 'username' | 'photo'>;
is_loading: boolean; is_loading: boolean;
is_succesfull: boolean; is_succesfull: boolean;
errors: Record<string, string>; errors: Record<string, string>;

View file

@ -8,12 +8,7 @@ import { EditorDialogAudio } from '~/containers/editors/EditorDialogAudio';
import { NODE_TYPES } from '../node/constants'; import { NODE_TYPES } from '../node/constants';
import { TestDialog } from '~/containers/dialogs/TestDialog'; import { TestDialog } from '~/containers/dialogs/TestDialog';
import { ProfileDialog } from '~/containers/dialogs/ProfileDialog'; import { ProfileDialog } from '~/containers/dialogs/ProfileDialog';
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
export const MODAL_ACTIONS = {
SET_SHOWN: 'MODAL.SET_SHOWN',
SET_DIALOG: 'SET_DIALOG',
SHOW_DIALOG: 'SHOW_DIALOG',
};
export const DIALOGS = { export const DIALOGS = {
EDITOR_IMAGE: 'EDITOR_IMAGE', EDITOR_IMAGE: 'EDITOR_IMAGE',
@ -23,25 +18,14 @@ export const DIALOGS = {
LOGIN: 'LOGIN', LOGIN: 'LOGIN',
LOADING: 'LOADING', LOADING: 'LOADING',
PROFILE: 'PROFILE', PROFILE: 'PROFILE',
RESTORE_REQUEST: 'RESTORE_REQUEST',
TEST: 'TEST', TEST: 'TEST',
}; };
export const DIALOG_CONTENT = { export const MODAL_ACTIONS = {
[DIALOGS.EDITOR_IMAGE]: EditorDialogImage, SET_SHOWN: 'MODAL.SET_SHOWN',
[DIALOGS.EDITOR_TEXT]: EditorDialogText, SET_DIALOG: 'SET_DIALOG',
[DIALOGS.EDITOR_VIDEO]: EditorDialogVideo, SHOW_DIALOG: 'SHOW_DIALOG',
[DIALOGS.EDITOR_AUDIO]: EditorDialogAudio,
[DIALOGS.LOGIN]: LoginDialog,
[DIALOGS.LOADING]: LoadingDialog,
[DIALOGS.TEST]: TestDialog,
[DIALOGS.PROFILE]: ProfileDialog,
};
export const NODE_EDITOR_DIALOGS = {
[NODE_TYPES.IMAGE]: DIALOGS.EDITOR_IMAGE,
[NODE_TYPES.TEXT]: DIALOGS.EDITOR_TEXT,
[NODE_TYPES.VIDEO]: DIALOGS.EDITOR_VIDEO,
[NODE_TYPES.AUDIO]: DIALOGS.EDITOR_AUDIO,
}; };
export interface IDialogProps { export interface IDialogProps {

View file

@ -40,7 +40,8 @@ import { selectFlowNodes, selectFlow } from '../flow/selectors';
import { URLS } from '~/constants/urls'; import { URLS } from '~/constants/urls';
import { selectNode } from './selectors'; import { selectNode } from './selectors';
import { IResultWithStatus, INode } from '../types'; import { IResultWithStatus, INode } from '../types';
import { NODE_EDITOR_DIALOGS, DIALOGS } from '../modal/constants'; import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs';
import { DIALOGS } from '~/redux/modal/constants';
import { INodeState } from './reducer'; import { INodeState } from './reducer';
import { IFlowState } from '../flow/reducer'; import { IFlowState } from '../flow/reducer';

View file

@ -1,7 +1,7 @@
import { DetailedHTMLProps, InputHTMLAttributes } from "react"; import { DetailedHTMLProps, InputHTMLAttributes } from 'react';
import { DIALOGS } from "~/redux/modal/constants"; import { DIALOGS } from '~/redux/modal/constants';
import { ERRORS } from "~/constants/errors"; import { ERRORS } from '~/constants/errors';
import { IUser } from "./auth/types"; import { IUser } from './auth/types';
export interface ITag { export interface ITag {
id: number; id: number;
@ -55,7 +55,7 @@ export interface IResultWithStatus<T> {
export type UUID = string; export type UUID = string;
export type IUploadType = "image" | "text" | "audio" | "video" | "other"; export type IUploadType = 'image' | 'text' | 'audio' | 'video' | 'other';
export interface IFile { export interface IFile {
id?: number; id?: number;
@ -96,12 +96,12 @@ export interface IFileWithUUID {
} }
export interface IBlockText { export interface IBlockText {
type: "text"; type: 'text';
text: string; text: string;
} }
export interface IBlockEmbed { export interface IBlockEmbed {
type: "video"; type: 'video';
url: string; url: string;
} }
@ -124,7 +124,7 @@ export interface INode {
is_heroic?: boolean; is_heroic?: boolean;
flow: { flow: {
display: "single" | "vertical" | "horizontal" | "quadro"; display: 'single' | 'vertical' | 'horizontal' | 'quadro';
show_description: boolean; show_description: boolean;
}; };
@ -147,7 +147,7 @@ export interface IComment {
update_at?: string; update_at?: string;
} }
export type IMessage = Omit<IComment, "user" | "node"> & { export type IMessage = Omit<IComment, 'user' | 'node'> & {
from: IUser; from: IUser;
to: IUser; to: IUser;
}; };
@ -155,7 +155,7 @@ export type IMessage = Omit<IComment, "user" | "node"> & {
export interface ICommentGroup { export interface ICommentGroup {
user: IUser; user: IUser;
comments: IComment[]; comments: IComment[];
ids: IComment["id"][]; ids: IComment['id'][];
} }
export type IUploadProgressHandler = (progress: ProgressEvent) => void; export type IUploadProgressHandler = (progress: ProgressEvent) => void;
@ -164,25 +164,25 @@ export type IValidationErrors = Record<string, IError>;
export type InputHandler<T = string> = (val: T) => void; export type InputHandler<T = string> = (val: T) => void;
export const NOTIFICATION_TYPES = { export const NOTIFICATION_TYPES = {
message: "message", message: 'message',
comment: "comment", comment: 'comment',
node: "node" node: 'node',
}; };
export type IMessageNotification = { export type IMessageNotification = {
type: typeof NOTIFICATION_TYPES["message"]; type: typeof NOTIFICATION_TYPES['message'];
content: Partial<IMessage>; content: Partial<IMessage>;
created_at: string; created_at: string;
}; };
export type ICommentNotification = { export type ICommentNotification = {
type: typeof NOTIFICATION_TYPES["comment"]; type: typeof NOTIFICATION_TYPES['comment'];
content: Partial<IComment>; content: Partial<IComment>;
created_at: string; created_at: string;
}; };
export type INodeNotification = { export type INodeNotification = {
type: typeof NOTIFICATION_TYPES["node"]; type: typeof NOTIFICATION_TYPES['node'];
content: Partial<INode>; content: Partial<INode>;
created_at: string; created_at: string;
}; };

View file

@ -12,6 +12,9 @@ $grass: #41800d;
$wisegreen: #007962; $wisegreen: #007962;
// $wisegreen: #006868; // $wisegreen: #006868;
$primary: $red;
$secondary: $wisegreen;
$red_gradient: linear-gradient(165deg, $orange -50%, $red 150%); $red_gradient: linear-gradient(165deg, $orange -50%, $red 150%);
$blue_gradient: linear-gradient(170deg, $green, $dark_blue); $blue_gradient: linear-gradient(170deg, $green, $dark_blue);
$green_gradient: linear-gradient( $green_gradient: linear-gradient(

View file

@ -96,6 +96,11 @@ body {
font-weight: bold; font-weight: bold;
} }
a {
color: $primary;
text-decoration: underline;
}
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 18px; width: 18px;
height: 18px; height: 18px;

View file

@ -5,6 +5,7 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const { join } = require('path'); const { join } = require('path');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Dotenv = require('dotenv-webpack'); const Dotenv = require('dotenv-webpack');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const htmlPlugin = new HtmlWebPackPlugin({ const htmlPlugin = new HtmlWebPackPlugin({
template: './src/index.html', template: './src/index.html',
@ -38,6 +39,13 @@ module.exports = () => {
filename: '[name].[contenthash].css', filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css', chunkFilename: '[id].[contenthash].css',
}), }),
new CircularDependencyPlugin({
// exclude: /node_modules/,
include: /LoginDialog/,
failOnError: true,
allowAsyncCycles: false,
cwd: process.cwd(),
}),
]; ];
return { return {