From fc5e4a0106751423b581c775235f82782eeacc9b Mon Sep 17 00:00:00 2001 From: srgooglo Date: Tue, 25 Aug 2020 02:55:20 +0200 Subject: [PATCH] update: app model, login & authframes --- .gitignore | 2 +- .umirc.js | 20 +- config/endpoints.js | 1 + config/index.js | 16 +- package.json | 3 +- src/components/Loader/Loader.js | 2 +- src/components/PostCreator/index.js | 322 ++++++++++++++++++++++++++ src/components/PostCreator/index.less | 315 +++++++++++++++++++++++++ src/components/index.js | 4 +- src/core/cores/index.js | 9 +- src/core/cores/router/index.js | 10 +- src/core/cores/session/index.js | 24 +- src/core/cores/user/index.js | 49 ++-- src/core/libs/v3_model/index.js | 4 - src/layouts/BaseLayout.js | 23 +- src/layouts/PrimaryLayout.js | 7 +- src/layouts/PublicLayout.js | 67 ++++++ src/models/app.js | 92 +++++--- src/pages/debug/index.js | 2 +- src/pages/explore/index.js | 9 + src/pages/index.js | 11 +- src/pages/login/index.js | 132 +++++++++++ src/pages/login/index.less | 234 +++++++++++++++++++ src/pages/login/login.js | 277 ++++++++++++++++++++++ src/pages/login/register.js | 162 +++++++++++++ 25 files changed, 1674 insertions(+), 123 deletions(-) create mode 100644 src/components/PostCreator/index.js create mode 100644 src/components/PostCreator/index.less create mode 100644 src/layouts/PublicLayout.js create mode 100644 src/pages/explore/index.js create mode 100644 src/pages/login/index.js create mode 100644 src/pages/login/index.less create mode 100644 src/pages/login/login.js create mode 100644 src/pages/login/register.js diff --git a/.gitignore b/.gitignore index 169c8f97..138e46f6 100755 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,4 @@ /src/.umi-production /src/.umi-test /.env.local -api/ + diff --git a/.umirc.js b/.umirc.js index ed1a8528..bbb3964c 100644 --- a/.umirc.js +++ b/.umirc.js @@ -1,25 +1,7 @@ import { defineConfig } from 'umi'; -const Path = require('path'); const { resolve } = require('path'); -const themePth = require('./src/theme/index.js') -const lessToJs = require('less-vars-to-js'); -const fs = require('fs'); -const AntDesignThemePlugin = require('antd-theme-webpack-plugin'); - -const options = { - antDir: Path.join(__dirname, './node_modules/antd'), - stylesDir: Path.join(__dirname, './src/styles'), - varFile: Path.join(__dirname, './src/styles/variables.less'), - themeVariables: ['@primary-color'], - indexFileName: 'index.html' -} - -const themePlugin = new AntDesignThemePlugin(options); - - -const convToVars = file => lessToJs(fs.readFileSync(Path.join(__dirname, file), 'utf8')) export default defineConfig({ hash: false, ignoreMomentLocale: true, @@ -33,7 +15,7 @@ export default defineConfig({ }, alias: { antd: resolve(__dirname, './node_modules/antd'), - api: resolve(__dirname, './node_modules/@ragestudio/ycorejs-lib'), + api: resolve(__dirname, './node_modules/@ragestudio/ycorejs-lib'), // ./api globals: resolve(__dirname, './globals'), core: resolve(__dirname, './src/core'), theme: resolve(__dirname, './src/theme'), diff --git a/config/endpoints.js b/config/endpoints.js index e2bfac28..ae323c5c 100644 --- a/config/endpoints.js +++ b/config/endpoints.js @@ -4,4 +4,5 @@ export default { logout: 'POST /logout', get_data: 'POST /get-user-data', + profileData: 'POST /early_user' }; diff --git a/config/index.js b/config/index.js index c5905bcf..72cdde8c 100644 --- a/config/index.js +++ b/config/index.js @@ -40,7 +40,7 @@ module.exports = { include: [/.*/] } ], - + // Default Behaviors defaults: { verbosity: false, @@ -50,14 +50,16 @@ module.exports = { render_pagetransition_preset: 'moveToRightScaleUp', feed_autorefresh: false, + }, - post_maxlenght: '512', - post_catchlimit: '20', - post_hidebar: true, + stricts: { + post_maxlenght: '512', + post_catchlimit: '20', + post_hidebar: true, - // In KB - api_maxpayload: '101376', - api_maxovertick: 10, + // In KB + api_maxpayload: '101376', + api_maxovertick: 10, } }; diff --git a/package.json b/package.json index 607c1a7a..a35e1e89 100755 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4", "title": "Comty™", "DevBuild": true, - "version": "0.8.08", + "version": "0.8.22", "stage": "dev-pre", "description": "", "author": "RageStudio", @@ -36,6 +36,7 @@ "@material-ui/core": "^4.9.9", "@material-ui/icons": "^4.9.1", "@ragestudio/ycorejs-lib": "^0.1.22", + "@steveeeie/react-page-transition": "^1.2.0", "antd": "^4.5.1", "axios": "^0.19.2", "babel-core": "^6.26.3", diff --git a/src/components/Loader/Loader.js b/src/components/Loader/Loader.js index 78f4b8da..132f9e48 100755 --- a/src/components/Loader/Loader.js +++ b/src/components/Loader/Loader.js @@ -4,7 +4,7 @@ import styles from './Loader.less' const Loader = (loading) => { return ( -
+
Loading...
({ app })) +class PostCreator extends React.PureComponent { + constructor(props) { + super(props), + this.state = { + maxFileSize: stricts.api_maxpayload, + maxTextLenght: stricts.post_maxlenght, + + renderValid: false, + loading: false, + + textLenght: stricts.post_maxlenght, + rawText: '', + posting: false, + postingResult: false, + shareWith: 'any', + + uploader: false, + uploaderFile: null, + uploaderFileOrigin: null, + }, + window.PostCreatorComponent = this + } + + dropRef = React.createRef() + + ToogleUploader() { + this.setState({ uploader: !this.state.uploader }) + } + handleDeleteFile = () => { + this.setState({ uploaderFile: null }) + } + handleFileUpload = info => { + if (info.file.status === 'uploading') { + this.setState({ loading: true }) + } + if (info.file.status === 'done') { + this.setState({ uploaderFileOrigin: info.file.originFileObj, uploader: false }) + + core.getBase64(info.file.originFileObj, fileURL => { + this.setState({ uploaderFile: fileURL, loading: false }) + }) + } + } + + beforeUpload = file => { + const filter = + file.type === 'image/jpeg' || + file.type === 'audio/mp3' || + file.type === 'audio/wav' || + file.type === 'audio/ogg' || + file.type === 'image/png' || + file.type === 'image/jpg' || + file.type === 'image/gif' || + file.type === 'video/mp4' + if (!filter) { + antd.message.error(`${file.type} This file is not valid!`) + } + const maxsize = file.size / 1024 / 1024 < stricts.api_maxpayload + if (!maxsize) { + antd.message.error( + `Image must smaller than ${stricts.api_maxpayload} KB!` + ) + } + return filter && maxsize + } + + handleChanges = ({ target: { value } }) => { + this.setState({ + rawText: value, + textLenght: this.state.maxTextLenght - value.length, + }) + } + + handleKeysProgressBar() { + return this.state.textLenght <= (this.state.maxTextLenght / 100) * 30? 'exception' : 'active' + } + + handleDragIn = e => { + e.preventDefault() + e.stopPropagation() + + this.state.uploader? this.setState({ uploader: true }) : null + } + + handleDragOut = e => { + e.preventDefault() + e.stopPropagation() + + this.state.uploader? null : this.setState({ uploader: false }) + } + + componentDidMount() { + // Validate for render + if (this.props.app.userData) { + this.setState({renderValid: true}) + } + + // const _this = this + // $('body').bind('paste', function(je) { + // var e = je.originalEvent + // for (var i = 0; i < e.clipboardData.items.length; i++) { + // var item = e.clipboardData.items[i] + // if (item.type.indexOf('image') != -1) { + // //item. + // let a; + // a = item.getAsFile() + // _this.setState({ uploaderFileOrigin: a }) + // core.ReadFileAsB64(a, res => { + // _this.setState({ uploaderFile: res }) + // }) + // } else { + // // ignore not images + // } + // } + // }) + // let div = this.dropRef.current + // div.addEventListener('dragenter', this.handleDragIn) + // div.addEventListener('dragleave', this.handleDragOut) + } + + componentWillUnmount() { + // let div = this.dropRef.current + // div.removeEventListener('dragenter', this.handleDragIn) + // div.removeEventListener('dragleave', this.handleDragOut) + } + + canPost() { + const isTypedSomething = this.state.textLenght < this.state.maxTextLenght + const isUploadedFile = this.state.uploaderFile ? true : false + + return isUploadedFile || isTypedSomething + } + + render() { + const { userData } = this.props.app + const { textLenght, uploaderFile } = this.state + + const GetPostPrivacy = { + bool: (e) => { + switch (e) { + case 'any': + return '0' + case 'only_followers': + return '1' + case 'only_follow': + return '2' + case 'private': + return '3' + default: + return '0' + } + }, + decorator: (e) => { + switch (e) { + case 'any': + return Share with everyone + case 'only_follow': + return Share with people I follow + case 'only_followers': + return Share with people follow me + case 'private': + return Dont share, only me + default: + return Unknown + } + }, + } + + const shareOptionsMenu = ( + this.setState({ shareWith: key })}> + + {GetPostPrivacy.decorator('any')} + + + {GetPostPrivacy.decorator('only_follow')} + + + {GetPostPrivacy.decorator('only_followers')} + + + {GetPostPrivacy.decorator('private')} + + + ) + + const PostCreator_Uploader = () => { + return( +
+ + + Drop your file here o click for upload + +
+ ) + } + + const PostCreator_InputText = () => { + return( + <> +
+ +
+ +
+ + ) : this.state.posting ? ( + + ) : ( + + ) + } + /> +
+ + ) + } + + + const PostCreatorComponent = () => { + return( + <> +
+ {this.state.uploader ? : } +
+
+ +
+ {uploaderFile ? this.renderPostPlayer(uploaderFile) : null} +
+ this.ToogleUpload()} + > + + {this.state.uploader ? ( + + ) : ( + + )} + + null}> + + + + e.preventDefault()} + > + {GetPostPrivacy.decorator(this.state.shareWith)} + + +
+ + ) + } + + const PostCreator_Invalid = () => { + return( +
+

This component cant be displayed!

+ +
+ ) + } + + return ( +
+ + { this.state.renderValid? : } + +
+ ) + } +} +export default PostCreator \ No newline at end of file diff --git a/src/components/PostCreator/index.less b/src/components/PostCreator/index.less new file mode 100644 index 00000000..1c46196c --- /dev/null +++ b/src/components/PostCreator/index.less @@ -0,0 +1,315 @@ +@import '~theme/index.less'; + +.cardWrapper { + // box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); + border-radius: 7px; + max-width: 510px; + min-width: 265px; + width: auto; + margin: 7px auto 50px auto; + + :global { + textarea { + font-weight: 500; + resize: none; + outline: none !important; + border: 0 !important; + } + + textarea:focus { + outline: none !important; + border: 0 !important; + } + + textarea:hover { + outline: none !important; + border: 0 !important; + } + + .ant-card-meta-detail>div:not(:last-child) { + margin: 0 + } + + .ant-card { + border-radius: 7px; + border: 0; + border-top: 1px solid #4646460c; + } + + .ant-card-body { + padding: 5px 15px 5px 15px; + } + + .ant-card-actions { + border-top: 0; + background: #EBEBEB; + opacity: 0; + height: 30px; + position: relative; + transition: opacity 150ms linear, position 150ms linear, transform 150ms linear; + border-radius: 0 0 10px 10px; + } + + .ant-card-actions:hover { + opacity: 1; + transform: translate(0, 15px); + transition: opacity 150ms linear, position 150ms linear, transform 150ms linear; + } + + .ant-card-actions>li { + margin: -20px 0 0 0; + border-right: 0; + + i { + + vertical-align: middle; + height: 40px; + width: 40px; + background-color: #fff; + border-radius: 24px; + } + + svg { + height: 20px; + width: 20px; + height: 100%; + vertical-align: middle; + } + } + } +} + +.titleAvatar { + width: 45px; + height: 45px; + display: flex; + + :global { + img { + width: 45px; + height: 45px; + border-radius: 12px; + } + } +} + +.inputWrapper { + display: flex; + z-index: 10; + position: relative; + width: 100%; + padding: 18px 7px 0 7px; + transition: height 150ms linear; + + :global { + .ant-btn-primary { + z-index: 10; + position: relative; + border-radius: 0 10px 10px 0; + height: 100%; + vertical-align: bottom; + border: none; + box-shadow: none; + } + + .ant-input { + z-index: 10; + position: relative; + border-color: transparent !important; + box-shadow: none; + border-radius: 3px 0 0 0; + height: 100%; + padding: 5px 10px 5px 10px; + transition: height 150ms linear; + width: 100%; + + } + + .ant-input:hover { + border-color: #1890ff; + } + + .ant-input-affix-wrapper { + height: 100%; + } + } +} + +.progressHandler { + z-index: 10; + position: relative; + margin: 0 7px 0 7px; + + :global { + .ant-progress-bg { + border-radius: 0 0 10px 10px; + } + + .ant-progress-inner { + border-radius: 0 0 14px 14px; + width: calc(100% - 32px); + vertical-align: top; + } + } +} + +.postExtra { + width: 100%; + height: 100%; + position: relative; + margin: 0 0 40px 0; + + .shareWith { + color: rgb(53, 53, 53); + float: right; + font-size: 11px; + line-height: 30px; + } + + :global { + .MuiSvgIcon-root { + width: 1em; + height: 1em; + display: inline-block; + font-size: 18px; + transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + flex-shrink: 0; + margin: 8px; + line-height: 1px; + user-select: none; + } + + .ant-btn .anticon { + transition: margin-left 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); + margin: 8px; + } + + .ant-btn { + width: 35px; + height: 35px; + float: left; + padding: 0; + border-radius: 11px; + margin: 0 10px; + background-color: #eeeeee; + border-color: transparent; + } + + .ant-btn:hover { + border-color: transparent; + } + + } +} + +.uploader { + display: flex; + position: relative; + border-radius: 10px; + z-index: 30; + width: 100%; + height: 100%; + + span { + width: 100%; + } + + :global { + .ant-upload.ant-upload-drag { + background: #fafafa; + border: 1px dashed #d9d9d9; + border-radius: 12px; + transition: border-color 0.3s; + } + + .anticon svg { + display: inline-block; + font-size: 30px; + } + } +} + +.imagePreviewWrapper { + position: relative; + width: 100%; + height: 100%; + // top: -100px; + margin: 0 0 15px 0; + background-color: #eeeeee; + + .imagePreview { + z-index: 5; + position: relative; + width: 50%; + margin: auto; + border-radius: 8px; + transition: all 150ms linear; + + img { + width: 100%; + border: 0.5px rgba(56, 56, 56, 0.459) solid; + } + + video { + width: 100%; + border: 0.5px rgba(56, 56, 56, 0.459) solid; + } + + transition: all 150ms linear; + + } + + .imageOverlay { + z-index: 10; + position: relative; + opacity: 0; + transition: all 150ms linear; + margin: auto; + } +} + +.imagePreviewWrapper:hover .imagePreview { + opacity: 0.5; + transition: all 150ms linear; +} + +.imagePreviewWrapper:hover .imageOverlay { + opacity: 1; + transition: all 150ms linear; + +} + +.proccessUnset { + opacity: 0; + transition: opacity 250ms linear; + animation: proccessUnset 250ms linear; +} + +.proccessSet { + transition: opacity 250ms linear; + animation: proccessSet 250ms linear; +} + +@keyframes proccessSet { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes proccessUnset { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.fontct { + font-family: "Poppins", sans-serif; +} \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js index 644c64a6..1d14a4e9 100755 --- a/src/components/index.js +++ b/src/components/index.js @@ -15,6 +15,7 @@ import UserBadges from './UserBadges' // Post Components import MediaPlayer from './MediaPlayer' +import PostCreator from './PostCreator' // Mix & Export all export { @@ -25,5 +26,6 @@ export { UserBadges, PageTransition, MyLayout, - Loader + Loader, + PostCreator } diff --git a/src/core/cores/index.js b/src/core/cores/index.js index 28bdfe76..46f2bec6 100644 --- a/src/core/cores/index.js +++ b/src/core/cores/index.js @@ -1,3 +1,6 @@ -export * from './session'; -export * from './user'; -export * from './router' \ No newline at end of file +export * from './router' + +import * as user from './user' +import * as session from './session' + +export { user, session } \ No newline at end of file diff --git a/src/core/cores/router/index.js b/src/core/cores/router/index.js index 6447eaaa..1002cc10 100644 --- a/src/core/cores/router/index.js +++ b/src/core/cores/router/index.js @@ -11,18 +11,18 @@ import { history } from 'umi'; * Specify the paths of the files, in this case it is pointing to the root */ export const router = { - go: e => { - goTo.element('primaryContent'); - router.push(e); - }, push: e => { history.push({ pathname: `${e}`, }); }, - goprofile: () => { + go: e => { + router.push(e); goTo.element('primaryContent'); + }, + goprofile: () => { router.push(`/@${e}`); + goTo.element('primaryContent'); }, }; diff --git a/src/core/cores/session/index.js b/src/core/cores/session/index.js index 14f6bb70..d9091ca2 100644 --- a/src/core/cores/session/index.js +++ b/src/core/cores/session/index.js @@ -1,46 +1,38 @@ -/** -* -* @param {HTMLTableElement} session - Callback / Credentials -* @returns {callback} make an API call to verify credentials -* @throws {NotFoundError} show error when credentials were not correctly put -* @async -* -* -*/ - import endpoints from 'config/endpoints'; import { v3_model } from 'core/libs'; - -// @param {Array} payload callback - check the information and if it is correct give access function auth(payload, callback) { if (!payload) return false; const { username, password, server_key } = payload; if (username && password) { + const frame = { username: atob(username), password: atob(password) } v3_model.api_request( { + body: frame, endpoint: endpoints.auth, serverKey: server_key, verbose: true, }, (err, res) => { - console.log(err, res); + return callback(err, res); }, ); - return callback(false, true); } else { const res = { status: 100, message: 'Invalid Credentials!' }; return callback(res, false); } } -async function deauth() {} +function deauth() { + +} -// check the information and if it is correct give access const backup = { get: () => {}, set: () => {}, }; + + export { auth, deauth, backup }; diff --git a/src/core/cores/user/index.js b/src/core/cores/user/index.js index 73d51fe8..e2c8d011 100644 --- a/src/core/cores/user/index.js +++ b/src/core/cores/user/index.js @@ -7,21 +7,28 @@ const set = { }, }; -const get = { - data: parms => { +export const get = { + data: (parms, callback) => { if (!parms) return false; - const { id, type } = parms; + const { id, access_token, serverKey, fetch } = parms; - if (!id) { + let req = { + fetch: fetch? fetch : 'user_data' + } + + if (!id || !access_token) { // core get id data from current session } v3_model.api_request( { + body: {user_id: id, fetch: req.fetch}, + serverKey: serverKey, + userToken: access_token, endpoint: endpoints.get_data, verbose: true, }, (err, res) => { - console.log(err, res); + return callback(err, res) }, ); }, @@ -33,17 +40,32 @@ const get = { // core get id data from current session } }, - profileData: parms => { - if (!parms) return false; - const { id } = parms; + profileData: (parms, callback) => { + if (!parms) return false - if (!id) { - // core get id data from current session + const { username } = parms + + if (username) { + v3_model.api_request( + { + body: { username }, + endpoint: endpoints.profileData, + verbose: true, + }, + (err, res) => { + err? console.error(err) : null + return callback(false, res); + }, + ); + + } else { + const res = { status: 105, message: 'Invalid Username!' }; + return callback(res, false); } }, }; -const actions = { +export const actions = { block: parms => { if (!parms) return false; const { id, toID } = parms; @@ -58,8 +80,3 @@ const actions = { }, }; -export { - //set - get, - actions, -}; diff --git a/src/core/libs/v3_model/index.js b/src/core/libs/v3_model/index.js index 4064ea03..dc36284a 100644 --- a/src/core/libs/v3_model/index.js +++ b/src/core/libs/v3_model/index.js @@ -1,13 +1,10 @@ import { lib, v3_request } from 'api'; import endpoints_list from 'config/endpoints'; import { app_config } from 'config'; -import * as core from 'core' -import { connect } from 'dva'; const { api_prefix } = app_config; const { uri_resolver } = lib; - async function compileURI(e, callback) { const resolvers = await uri_resolver(); const prefix = resolvers[api_prefix]; @@ -15,7 +12,6 @@ async function compileURI(e, callback) { let final = null; let url; let method; - const endpointSplit = e.split(' '); if (endpointSplit.length === 2) { method = endpointSplit[0]; diff --git a/src/layouts/BaseLayout.js b/src/layouts/BaseLayout.js index ecb0de2a..abe1bf21 100755 --- a/src/layouts/BaseLayout.js +++ b/src/layouts/BaseLayout.js @@ -1,4 +1,4 @@ -import React, { PureComponent, Fragment } from 'react' +import React from 'react' import PropTypes from 'prop-types' import { Helmet } from 'react-helmet' import { Loader } from 'components' @@ -8,39 +8,44 @@ import { queryLayout } from 'core' import config from 'config' import PrimaryLayout from './PrimaryLayout' +import PublicLayout from './PublicLayout' import './BaseLayout.less' const LayoutMap = { - primary: PrimaryLayout - // public: PublicLayout, + primary: PrimaryLayout, + public: PublicLayout, } @withRouter @connect(({ app, loading }) => ({ app, loading })) -class BaseLayout extends PureComponent { +class BaseLayout extends React.Component { previousPath = '' + renderLoading = true render() { const { loading, children, location } = this.props const Container = LayoutMap[queryLayout(config.layouts, location.pathname)] - const currentPath = location.pathname + location.search + if (currentPath !== this.previousPath) { NProgress.start() + this.renderLoading = true } if (!loading.global) { NProgress.done() this.previousPath = currentPath + this.renderLoading = false } + return ( - + {config.app_config.siteName} - {Loader(loading)} - {children} - + {Loader(this.renderLoading)} + {children} + ) } } diff --git a/src/layouts/PrimaryLayout.js b/src/layouts/PrimaryLayout.js index ee62df49..3fa23546 100755 --- a/src/layouts/PrimaryLayout.js +++ b/src/layouts/PrimaryLayout.js @@ -5,7 +5,6 @@ import PropTypes from 'prop-types' import {withRouter, connect} from 'umi' import { MyLayout, - PageTransition, } from 'components' import { enquireScreen, unenquireScreen } from 'enquire-js' import store from 'store' @@ -103,17 +102,13 @@ class PrimaryLayout extends React.Component {
- + {children? children : null} -
diff --git a/src/layouts/PublicLayout.js b/src/layouts/PublicLayout.js new file mode 100644 index 00000000..87f47aee --- /dev/null +++ b/src/layouts/PublicLayout.js @@ -0,0 +1,67 @@ +import React from 'react' +import store from 'store' + +import { + MyLayout, + PageTransition, +} from 'components' +import { enquireScreen, unenquireScreen } from 'enquire-js' +import classnames from 'classnames' + +import * as antd from 'antd' +import * as Icons from 'components/Icons' + +import styles from './PrimaryLayout.less' + +const { Content } = antd.Layout + +export default class PublicLayout extends React.Component { + constructor(props) { + super(props) + window.PrimaryComponent = this + this.state = { + isMobile: false, + } + } + + componentDidMount() { + this.enquireHandler = enquireScreen(mobile => { + const { isMobile } = this.state + if (isMobile !== mobile) { + this.setState({ + isMobile: mobile, + }) + store.set('mobile_src', mobile) + } + }) + } + + componentWillUnmount() { + unenquireScreen(this.enquireHandler) + } + + + render() { + const { children } = this.props + const { isMobile } = this.state + return ( + + +
+ + + {children} + + +
+
+
+ ) + } +} \ No newline at end of file diff --git a/src/models/app.js b/src/models/app.js index 76c09efb..68fdb6f1 100755 --- a/src/models/app.js +++ b/src/models/app.js @@ -3,10 +3,9 @@ import store from 'store'; import { pathMatchRegexp, queryLayout } from 'core'; import { app_config } from 'config'; import keys from 'config/app_keys'; -import * as core from 'core'; -import { session } from 'core/cores'; +import { router } from 'core/cores'; import verbosity from 'core/libs/verbosity' -import { theme } from 'core/libs/style' +import { notify } from 'core/libs/interface/notify' export default { namespace: 'app', @@ -17,7 +16,7 @@ export default { ng_services: false, session_valid: false, - session_token: null, + session_token: sessionStorage.getItem('session'), session_data: null, session_uuid: null, @@ -63,30 +62,31 @@ export default { effects: { *query({ payload }, { call, put, select }) { const service = yield select(state => state.app.service_valid); + const session = yield select(state => state.app.session_valid); + + yield put({ type: 'updateFrames' }) + if (!service) { console.error('❌ Cannot connect with validate session service!'); - return yield put({ - type: 'updateState', - payload: { service_valid: false }, - }); } - if (session) { - if (pathMatchRegexp(['/', '/login'], window.location.pathname)) { - app.router.push({ pathname: `${app_config.MainPath}` }); - } - return true; - } else if ( - !pathMatchRegexp(['', '/login'], window.location.pathname) && - queryLayout(config.layouts, window.location.pathname) !== 'public' - ) { - if (validBackup == true) { - // logout normal - } else { - core.router.push({ pathname: '/login' }); - } - } + // if (session) { + // if (pathMatchRegexp(['/', '/login'], window.location.pathname)) { + // app.router.push({ pathname: `${app_config.MainPath}` }); + // } + + // return true; + // } else if ( + // !pathMatchRegexp(['', '/login'], window.location.pathname) && + // queryLayout(config.layouts, window.location.pathname) !== 'public' + // ) { + // if (validBackup == true) { + // // logout normal + // } else { + // core.router.push({ pathname: '/login' }); + // } + // } }, *update({ payload }, { call, put, select }) { const session = yield select(state => state.app.session_valid); @@ -105,14 +105,10 @@ export default { }, *login({ payload }, { call, put, select }) { if (!payload) return false; - const serverKey = yield select(state => state.app.server_key); - const requestPayload = { username: payload.username, password: payload.password, server_key: serverKey } - session.auth(requestPayload, (err, res) => { - if (err) { - const { status, message } = err; - return console.log(status, message); - } - }); + + const { user_id, access_token } = payload.authFrame + + return yield put({ type: 'handleLogin', payload: { user_id, access_token, user_data: payload.dataFrame } }) }, *updateTheme({payload}, {put, select}){ if (!payload) return false @@ -146,6 +142,40 @@ export default { ...payload, }; }, + updateFrames(state) { + let sessionAuthframe = sessionStorage.getItem('session') + let sessionDataframe = sessionStorage.getItem('data') + + try { + if (sessionAuthframe) { + sessionAuthframe = JSON.parse(atob(sessionAuthframe)) + } + if (sessionDataframe) { + sessionDataframe = JSON.parse(atob(sessionDataframe)) + } + + state.session_token = sessionAuthframe.session_token, + state.session_uuid = sessionAuthframe.session_uuid + state.session_data = sessionDataframe + } catch (error) { + verbosity.error(error) + } + }, + handleLogin(state, { payload }){ + if (!payload) return false + + state.session_token = payload.access_token + state.session_uuid = payload.user_id + state.session_data = payload.user_data + + const sessionAuthframe = btoa(JSON.stringify({session_token: payload.access_token, session_uuid: payload.user_id})) + const sessionDataframe = btoa(payload.user_data) + + sessionStorage.setItem('session', sessionAuthframe) + sessionStorage.setItem('data', sessionDataframe) + notify.success('Login done!') + router.push('/') + }, handleThemeChange(state, { payload }) { store.set('theme', payload); diff --git a/src/pages/debug/index.js b/src/pages/debug/index.js index 35e8734c..23701719 100644 --- a/src/pages/debug/index.js +++ b/src/pages/debug/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { request } from '@ragestudio/ycorejs-lib'; +import { request } from 'api'; import { Row, Col, diff --git a/src/pages/explore/index.js b/src/pages/explore/index.js new file mode 100644 index 00000000..8fea6898 --- /dev/null +++ b/src/pages/explore/index.js @@ -0,0 +1,9 @@ +import React from 'react' +import { PostCreator } from 'components' +export default class Explore_Page extends React.Component{ + render(){ + return( + + ) + } +} \ No newline at end of file diff --git a/src/pages/index.js b/src/pages/index.js index 7fedc64a..edffea5b 100755 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,6 +1,7 @@ import React from 'react'; import { connect } from 'umi'; import * as antd from 'antd' +import * as Icons from 'components/Icons' @connect(({ app }) => ({ app })) class PageIndex extends React.PureComponent { @@ -37,7 +38,13 @@ class PageIndex extends React.PureComponent { } const map = tmp.map(e => { - return(

{e.key}

{JSON.stringify(e.value)}
) + const v = JSON.stringify(e.value) + return( +
+

{e.key}

+ {v.length < 500? {v} : {v}} +
+ ) }) return map @@ -45,7 +52,7 @@ class PageIndex extends React.PureComponent { return (
- + Redux state}> {AppState()} diff --git a/src/pages/login/index.js b/src/pages/login/index.js new file mode 100644 index 00000000..506f85b4 --- /dev/null +++ b/src/pages/login/index.js @@ -0,0 +1,132 @@ +import React from 'react' +import { app_info } from 'core' +import styles from './index.less' +import classnames from 'classnames' + +import * as antd from 'antd' +import * as Icons from 'components/Icons' + +import { RegistrationForm } from './register.js' +import { NormalLoginForm } from './login.js' + +import { app_config } from 'config' + +export function transitionToogle() { + window.LoginComponent.setState({ + transition: !window.LoginComponent.state.transition, + }) + window.LoginComponent.toogleYulioID() +} + +class Login extends React.PureComponent { + constructor(props) { + super(props) + window.LoginComponent = this + this.state = { + transition: false, + using: 1, + } + } + switchType = { + f: a => { + this.setState({ using: a }) + }, + login: () => { + this.switchType.f(1) + }, + register: () => { + this.switchType.f(2) + }, + forgot: () => { + this.switchType.f(3) + }, + } + + renderType(t) { + const a = this.state.using + if (t) { + switch (a) { + case 1: + return `Sign in ${app_config.siteName}` + case 2: + return 'Register' + case 3: + return 'Forgot' + default: + return 'Auth' + } + } else { + switch (a) { + case 1: + return + case 2: + return + case 3: + return null + default: + return + } + } + } + + renderHelperButtons = () => { + if (this.state.using == 1) { + return ( +
+ this.switchType.forgot()}> + Forgotten password + + this.switchType.register()}> + Create an account + +
+ ) + } + if (this.state.using == 2 || 3) { + return ( +
+ this.switchType.login()}> + Login + +
+ ) + } + } + + render() { + return ( +
+
+ ⚠ Using v{app_info.version} {app_info.stage} +
+ +
+
+
+
+ YulioID™ +
+

{this.renderType(true)}

+
+
+ {this.renderType()} + {this.renderHelperButtons()} +
+
+
+
+ ) + } +} +export default Login diff --git a/src/pages/login/index.less b/src/pages/login/index.less new file mode 100644 index 00000000..cf7bb1dc --- /dev/null +++ b/src/pages/login/index.less @@ -0,0 +1,234 @@ +@import '~theme/index.less'; + +.login_wrapper{ + width: 100%; + height: 100%; + font-family: "Poppins", sans-serif!important; + h1,h2,h3,h4,h5,h6{color: #333;} + position: absolute; + top: 0; + left: 0; + display: flex; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + margin: auto; + + overflow-y: scroll; + overflow-x: hidden; + &.goOut{ + .auth_box{ + -webkit-animation-name: fadeOutLeft; + animation-name: fadeOutLeft; + } + } + transition: all 300ms ease-in-out; +} + + +.auth_box{ + display: flex; + transition: all 300ms ease-in-out; + + .yid_logo { + vertical-align: middle; + height: 17px; + } + :global{ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus { + border: 0; + -webkit-text-fill-color: #333; + -webkit-box-shadow: 0 0 0px 1000px #ffffff98 inset; + box-shadow: #fff 0px 0px 0px 1000px inset; + transition: background-color 5000s ease-in-out 0s; + } + + .ant-input-affix-wrapper { + width: 100%; + height: 40px; + padding: 4px 11px; + color: #333; + font-size: 14px; + line-height: 1.5715; + background-color: #fff; //rgba(255, 255, 255, 0.596); + border: 1.5px #2F66DF solid; + border-radius: 7px; + } + } +} + +.centering_wrapper{ + width: 100%; + text-align: center; +} + +.left_body{ + z-index: 50; + transform: translate(12px,0); + float: left; + width: 30%; + color: #333; + background-color: #fff; + padding: 20px; + border-radius: 12px 0 0 12px; + box-shadow: 0px 10px 20px 0px rgba(51,51,51,0.52); + transition: all 300ms ease-in-out; + +} +.right_body{ + z-index: 51; + float: right; + width: 70%; + max-height: -webkit-fill-available; + height: 150px; + padding: 20px 50px 20px 50px; + color: #333; + background-color: #fff; + border-radius: 12px; + box-shadow: 0px 10px 20px 0px rgba(51,51,51,0.52); + transition: all 300ms ease-in-out; +} + + + +.helper_login_btn{ + transform: translate(-20px, -14px); +} + + +.login_helper_footer{ + width: 100%; + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + margin: auto; + :global{ + .ant-btn{ + margin: auto; + padding: 0 5px 0 5px; + } + } + + transform: translate(0, -10px); + +} + + +@keyframes go-out { + 0% { + filter: blur(0px) + } + + 100% { + filter: blur(15px) + } +} + +// // Full format +// @media (min-width: 486px){ +// .login_wrapper { +// min-height: 580px; +// } +// .auth_box { +// width: 784px; +// } +// } + +// Medium format max-width: 830px +@media (min-width: 486px){ + .auth_box { + padding: 0 16px 40px; + width: 500px; + min-height: 500px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + .left_body{ + width: 100%; + float: none; + border-radius: 12px 12px 0 0; + padding: 20px 20px 20px 20px; + transform: translate(0, 22px); + } + .right_body{ + width: 100%; + float: none; + padding: 20px 60px 20px 60px; + } +} + +// Mobile format +@media (max-width: 485px){ + .auth_box { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 70px 16px 40px; + width: 100%; + height: 100%; + min-height: 500px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border-radius: 0; + } + .left_body{ + box-shadow: none; + width: 100%; + float: none; + position: absolute; + top: 0; + margin-top: 30px; + transform: translate(0, 0); + } + .right_body{ + box-shadow: none; + width: 100%; + float: none; + padding: 20px 20px 20px 20px; + } +} + +.register_form{ + +} + +@-webkit-keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} diff --git a/src/pages/login/login.js b/src/pages/login/login.js new file mode 100644 index 00000000..c9330f9c --- /dev/null +++ b/src/pages/login/login.js @@ -0,0 +1,277 @@ +import React from 'react' +import styles from './index.less' + +import Fade from 'react-reveal/Fade' +import HeadShake from 'react-reveal/HeadShake'; + +import * as antd from 'antd' + +import { session, user } from 'core/cores' + +import verbosity from 'core/libs/verbosity' + +import { Form, Input, Button, Checkbox } from 'antd' +import { + UserOutlined, + LockOutlined, + BulbOutlined, + SwapLeftOutlined +} from 'components/Icons' +import { connect } from 'umi' + +@connect(({ app }) => ({ app })) +export class NormalLoginForm extends React.PureComponent { + state = { + activeForm: true, + step: 1, + validating: false, + error_count: 0, + step_error: false, + step_show: true, + swpass: false, + } + + next = values => { + let a = this.state.step + const b = btoa(Object.values(values).toString()) + switch (a) { + case 1: + const payload = { username: Object.values(values).toString() } + user.get.profileData(payload, (err, res) => { + if (err || !res) return false + try { + const res_data = JSON.parse(res) + + if (res_data.api_status == 200) { + a++ + this.anim_transition(300) + this.setState({ + step_error: false, + early_data: res_data.data, + form_rawd_1: b, + step: a, + }) + } + if (res_data.api_status == 400) { + this.anim_error() + } + } catch (error) { + return false + } + }) + + return true + case 2: + this.setState({ form_rawd_2: b, step: a }) + this.auth() + return true + default: + return false + } + } + + back() { + let a = this.state.step + if (a > 1) { + a-- + this.anim_transition(150) + } + + this.setState({ step: a }) + } + + anim_transition(duration) { + this.setState({ step_show: false }) + setTimeout(() => { + this.setState({ step_show: true }) + }, duration || 1000) + } + + anim_error() { + this.setState({ step_error: true, error_count: (this.state.error_count + 1) }) + } + + anim_close() { + this.setState({ step_show: false }) + } + + + getAuthFrame(payload) { + return new Promise(resolve => { + session.auth(payload, (err, res) => { + if (err) { + + } + if (res) { + try { + res = JSON.parse(res) + verbosity.log(res) + } catch (error) { + console.log('Invalid response!') + } + + switch (res.api_status.toString()) { + case "200": { + try { + return resolve(res) + } catch (error) { + verbosity.error(error) + } + break; + } + case "400": { + console.log('Credentials error') + this.setState({ validating: false }) + return this.anim_error() + } + case "500": { + console.log('Server error') + this.setState({ validating: false }) + return this.back() + } + default: { + console.log('Unknown error') + this.setState({ validating: false }) + return this.back() + } + } + + } + }) + }); + } + + getDataFrame(payload) { + return new Promise(resolve => { + user.get.data(payload, (err, res) => { + if(err) { + + } + if (res) { + try { + return resolve(JSON.stringify(JSON.parse(res)['user_data'])) + } catch (error) { + verbosity.error(error) + } + } + }) + + }) + } + + async auth() { + const { form_rawd_1, form_rawd_2 } = this.state + if (!form_rawd_1 || !form_rawd_2) return false + this.setState({ step_error: false, validating: true }) + + const authFrame = await this.getAuthFrame({username: form_rawd_1, password: form_rawd_2, server_key: this.props.app.server_key}) + const dataFrame = await this.getDataFrame({id: authFrame.user_id, access_token: authFrame.access_token, serverKey: this.props.app.server_key}) + + return this.props.dispatch({ + type: 'app/login', + payload: {authFrame, dataFrame} + }); + } + + renderState = () => { + switch (this.state.step) { + case 1: + return ( +
+
+ You can use your YulioID account to login +
+ + + } + placeholder="Username or Email" + /> + + + +
+ ) + case 2: + return ( +
+ +

Welcome Back @{this.state.early_data.username}

+ + + } + type={this.state.swpass ? 'text' : 'password'} + placeholder="Password" + /> + + +
+ } + type="link" + onClick={() => this.back()} + > + Back + + +
+
+ ) + case 3: { + return

Wait a sec...

+ } + default: + return null + } + } + + render() { + return ( +
+ + {this.state.activeForm? this.renderState() :

Mmm, this is taking longer than it should...

} +
+
+ ) + } +} diff --git a/src/pages/login/register.js b/src/pages/login/register.js new file mode 100644 index 00000000..936946d4 --- /dev/null +++ b/src/pages/login/register.js @@ -0,0 +1,162 @@ +import React, { useState } from 'react' +import { + MailOutlined, + TagOutlined, + LockOutlined, +} from '@ant-design/icons' + +import styles from './index.less' +import { + Form, + Input, + Tooltip, + Cascader, + Select, + Row, + Col, + Checkbox, + Button, + AutoComplete, +} from 'antd' +import { QuestionCircleOutlined } from '@ant-design/icons' +import ReCAPTCHA from 'react-google-recaptcha' +import { g_recaptcha_key } from 'config' + +function capchaOnChange(value) { + console.log('Captcha value:', value) +} + + + +export const RegistrationForm = () => { + + const onFinish = values => { + console.log('Received values of form: ', values) + } + + return ( +
+
+ + } + placeholder="ramdomuser"/> + + + } + placeholder="example@no-real.com" + /> + + + + } + placeholder="example@no-real.com"/> + + + ({ + validator(rule, value) { + if (!value || getFieldValue('password') === value) { + return Promise.resolve() + } + + return Promise.reject( + 'The two passwords that you entered do not match!' + ) + }, + }), + ]} + > + } + placeholder="example@no-real.com"/> + + + + + + + + + + + + + + + value + ? Promise.resolve() + : Promise.reject('Should accept agreement'), + }, + ]} + > + + I have read the agreement + + + + + +
+
+ ) +} \ No newline at end of file