2
This commit is contained in:
154
src/App.js
Normal file
154
src/App.js
Normal file
@@ -0,0 +1,154 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {goBack, closeModal, setStory} from "./js/store/router/actions";
|
||||
import {getActivePanel} from "./js/services/_functions";
|
||||
import * as VK from './js/services/VK';
|
||||
|
||||
import {Epic, View, Root, Tabbar, ModalRoot, TabbarItem, ConfigProvider} from "@vkontakte/vkui";
|
||||
|
||||
import Icon28Newsfeed from '@vkontakte/icons/dist/28/newsfeed';
|
||||
import Icon28More from '@vkontakte/icons/dist/28/more';
|
||||
|
||||
import HomePanelBase from './js/panels/home/base';
|
||||
import HomePanelGroups from './js/panels/home/groups';
|
||||
|
||||
import MorePanelBase from './js/panels/more/base';
|
||||
import MorePanelExample from './js/panels/more/example';
|
||||
|
||||
import HomeBotsListModal from './js/components/modals/HomeBotsListModal';
|
||||
import HomeBotInfoModal from './js/components/modals/HomeBotInfoModal';
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.lastAndroidBackAction = 0;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {goBack, dispatch} = this.props;
|
||||
|
||||
dispatch(VK.initApp());
|
||||
|
||||
window.onpopstate = () => {
|
||||
let timeNow = +new Date();
|
||||
|
||||
if (timeNow - this.lastAndroidBackAction > 500) {
|
||||
this.lastAndroidBackAction = timeNow;
|
||||
|
||||
goBack();
|
||||
} else {
|
||||
window.history.pushState(null, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
const {activeView, activeStory, activePanel, scrollPosition} = this.props;
|
||||
|
||||
if (
|
||||
prevProps.activeView !== activeView ||
|
||||
prevProps.activePanel !== activePanel ||
|
||||
prevProps.activeStory !== activeStory
|
||||
) {
|
||||
let pageScrollPosition = scrollPosition[activeStory + "_" + activeView + "_" + activePanel] || 0;
|
||||
|
||||
window.scroll(0, pageScrollPosition);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {goBack, setStory, closeModal, popouts, activeView, activeStory, activeModals, panelsHistory, colorScheme} = this.props;
|
||||
|
||||
let history = (panelsHistory[activeView] === undefined) ? [activeView] : panelsHistory[activeView];
|
||||
let popout = (popouts[activeView] === undefined) ? null : popouts[activeView];
|
||||
let activeModal = (activeModals[activeView] === undefined) ? null : activeModals[activeView];
|
||||
|
||||
const homeModals = (
|
||||
<ModalRoot activeModal={activeModal}>
|
||||
<HomeBotsListModal
|
||||
id="MODAL_PAGE_BOTS_LIST"
|
||||
onClose={() => closeModal()}
|
||||
/>
|
||||
<HomeBotInfoModal
|
||||
id="MODAL_PAGE_BOT_INFO"
|
||||
onClose={() => closeModal()}
|
||||
/>
|
||||
</ModalRoot>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfigProvider isWebView={true} scheme={colorScheme}>
|
||||
<Epic activeStory={activeStory} tabbar={
|
||||
<Tabbar>
|
||||
<TabbarItem
|
||||
onClick={() => setStory('home', 'base')}
|
||||
selected={activeStory === 'home'}
|
||||
><Icon28Newsfeed/></TabbarItem>
|
||||
<TabbarItem
|
||||
onClick={() => setStory('more', 'callmodal')}
|
||||
selected={activeStory === 'more'}
|
||||
><Icon28More/></TabbarItem>
|
||||
</Tabbar>
|
||||
}>
|
||||
<Root id="home" activeView={activeView} popout={popout}>
|
||||
<View
|
||||
id="home"
|
||||
modal={homeModals}
|
||||
activePanel={getActivePanel("home")}
|
||||
history={history}
|
||||
onSwipeBack={() => goBack()}
|
||||
>
|
||||
<HomePanelBase id="base" withoutEpic={false}/>
|
||||
<HomePanelGroups id="groups"/>
|
||||
</View>
|
||||
</Root>
|
||||
<Root id="more" activeView={activeView} popout={popout}>
|
||||
<View
|
||||
id="more"
|
||||
modal={homeModals}
|
||||
activePanel={getActivePanel("more")}
|
||||
history={history}
|
||||
onSwipeBack={() => goBack()}
|
||||
>
|
||||
<MorePanelBase id="callmodal"/>
|
||||
</View>
|
||||
<View
|
||||
id="modal"
|
||||
modal={homeModals}
|
||||
activePanel={getActivePanel("modal")}
|
||||
history={history}
|
||||
onSwipeBack={() => goBack()}
|
||||
>
|
||||
<MorePanelExample id="filters"/>
|
||||
</View>
|
||||
</Root>
|
||||
</Epic>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
activeView: state.router.activeView,
|
||||
activeStory: state.router.activeStory,
|
||||
panelsHistory: state.router.panelsHistory,
|
||||
activeModals: state.router.activeModals,
|
||||
popouts: state.router.popouts,
|
||||
scrollPosition: state.router.scrollPosition,
|
||||
|
||||
colorScheme: state.vkui.colorScheme
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
dispatch,
|
||||
...bindActionCreators({setStory, goBack, closeModal}, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
126
src/AppWithoutEpic.js
Normal file
126
src/AppWithoutEpic.js
Normal file
@@ -0,0 +1,126 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {goBack, closeModal} from "./js/store/router/actions";
|
||||
import {getActivePanel} from "./js/services/_functions";
|
||||
import * as VK from './js/services/VK';
|
||||
|
||||
import {View, Root, ModalRoot, ConfigProvider} from "@vkontakte/vkui";
|
||||
|
||||
import HomePanelProfile from './js/panels/home/base';
|
||||
import HomePanelGroups from './js/panels/home/groups';
|
||||
|
||||
import HomeBotsListModal from './js/components/modals/HomeBotsListModal';
|
||||
import HomeBotInfoModal from './js/components/modals/HomeBotInfoModal';
|
||||
|
||||
import MorePanelExample from './js/panels/more/example';
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.lastAndroidBackAction = 0;
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const {goBack, dispatch} = this.props;
|
||||
|
||||
dispatch(VK.initApp());
|
||||
|
||||
window.onpopstate = () => {
|
||||
let timeNow = +new Date();
|
||||
|
||||
if (timeNow - this.lastAndroidBackAction > 500) {
|
||||
this.lastAndroidBackAction = timeNow;
|
||||
|
||||
goBack();
|
||||
} else {
|
||||
window.history.pushState(null, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
const {activeView, activeStory, activePanel, scrollPosition} = this.props;
|
||||
|
||||
if (
|
||||
prevProps.activeView !== activeView ||
|
||||
prevProps.activePanel !== activePanel ||
|
||||
prevProps.activeStory !== activeStory
|
||||
) {
|
||||
let pageScrollPosition = scrollPosition[activeStory + "_" + activeView + "_" + activePanel] || 0;
|
||||
|
||||
window.scroll(0, pageScrollPosition);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {goBack, closeModal, popouts, activeView, activeModals, panelsHistory, colorScheme} = this.props;
|
||||
|
||||
let history = (panelsHistory[activeView] === undefined) ? [activeView] : panelsHistory[activeView];
|
||||
let popout = (popouts[activeView] === undefined) ? null : popouts[activeView];
|
||||
let activeModal = (activeModals[activeView] === undefined) ? null : activeModals[activeView];
|
||||
|
||||
const homeModals = (
|
||||
<ModalRoot activeModal={activeModal}>
|
||||
<HomeBotsListModal
|
||||
id="MODAL_PAGE_BOTS_LIST"
|
||||
onClose={() => closeModal()}
|
||||
/>
|
||||
<HomeBotInfoModal
|
||||
id="MODAL_PAGE_BOT_INFO"
|
||||
onClose={() => closeModal()}
|
||||
/>
|
||||
</ModalRoot>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfigProvider isWebView={true} scheme={colorScheme}>
|
||||
<Root activeView={activeView} popout={popout}>
|
||||
<View
|
||||
id="home"
|
||||
modal={homeModals}
|
||||
activePanel={getActivePanel("home")}
|
||||
history={history}
|
||||
onSwipeBack={() => goBack()}
|
||||
>
|
||||
<HomePanelProfile id="base" withoutEpic={true}/>
|
||||
<HomePanelGroups id="groups"/>
|
||||
</View>
|
||||
<View
|
||||
id="modal"
|
||||
modal={homeModals}
|
||||
activePanel={getActivePanel("modal")}
|
||||
history={history}
|
||||
onSwipeBack={() => goBack()}
|
||||
>
|
||||
<MorePanelExample id="filters"/>
|
||||
</View>
|
||||
</Root>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
activeView: state.router.activeView,
|
||||
activeStory: state.router.activeStory,
|
||||
panelsHistory: state.router.panelsHistory,
|
||||
activeModals: state.router.activeModals,
|
||||
popouts: state.router.popouts,
|
||||
scrollPosition: state.router.scrollPosition,
|
||||
|
||||
colorScheme: state.vkui.colorScheme
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
dispatch,
|
||||
...bindActionCreators({goBack, closeModal}, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
23
src/css/main.css
Normal file
23
src/css/main.css
Normal file
@@ -0,0 +1,23 @@
|
||||
.div-center {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.div-center img {
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.buttons-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.buttons-group button:first-child {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
a, div, img, p, button {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
31
src/index.js
Normal file
31
src/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/set';
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import {applyMiddleware, createStore} from "redux";
|
||||
import thunk from 'redux-thunk';
|
||||
import {Provider} from 'react-redux';
|
||||
import rootReducer from './js/store/reducers';
|
||||
import {composeWithDevTools} from 'redux-devtools-extension';
|
||||
|
||||
import {setStory} from "./js/store/router/actions";
|
||||
|
||||
import '@vkontakte/vkui/dist/vkui.css';
|
||||
import './css/main.css';
|
||||
|
||||
import App from './App';
|
||||
|
||||
export const store = createStore(rootReducer, composeWithDevTools(
|
||||
applyMiddleware(thunk),
|
||||
));
|
||||
|
||||
store.dispatch(setStory('home', 'base'));
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App/>
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
24
src/js/components/GroupCell.js
Normal file
24
src/js/components/GroupCell.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
|
||||
import {Cell, Avatar} from "@vkontakte/vkui";
|
||||
|
||||
class GroupCell extends PureComponent {
|
||||
|
||||
render() {
|
||||
const {description, photo, name} = this.props;
|
||||
|
||||
let desc = description.length > 0 ? description : "Описание отсутствует";
|
||||
|
||||
return (
|
||||
<Cell
|
||||
description={desc}
|
||||
before={<Avatar size={40} src={photo}/>}
|
||||
>
|
||||
{name}
|
||||
</Cell>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GroupCell;
|
||||
59
src/js/components/modals/HomeBotInfoModal.js
Normal file
59
src/js/components/modals/HomeBotInfoModal.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {Cell, List, Avatar, InfoRow, ModalPage, ModalPageHeader, PanelHeaderButton, withPlatform, IOS} from "@vkontakte/vkui";
|
||||
|
||||
import Icon24Dismiss from '@vkontakte/icons/dist/24/dismiss';
|
||||
import Icon24Cancel from '@vkontakte/icons/dist/24/cancel';
|
||||
|
||||
class HomeBotsListModal extends React.Component {
|
||||
|
||||
render() {
|
||||
const {id, onClose, platform} = this.props;
|
||||
|
||||
return (
|
||||
<ModalPage
|
||||
id={id}
|
||||
header={
|
||||
<ModalPageHeader
|
||||
left={platform !== IOS &&
|
||||
<PanelHeaderButton onClick={onClose}><Icon24Cancel/></PanelHeaderButton>}
|
||||
right={platform === IOS &&
|
||||
<PanelHeaderButton onClick={onClose}><Icon24Dismiss/></PanelHeaderButton>}
|
||||
>
|
||||
Информация о боте
|
||||
</ModalPageHeader>
|
||||
}
|
||||
onClose={onClose}
|
||||
settlingHeight={80}
|
||||
>
|
||||
<Cell
|
||||
description="Описание"
|
||||
before={<Avatar size={40} src="https://vk.com/images/community_100.png?ava=1"/>}
|
||||
>
|
||||
Название
|
||||
</Cell>
|
||||
<List>
|
||||
<Cell>
|
||||
<InfoRow header="Подписчиков">
|
||||
8800
|
||||
</InfoRow>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<InfoRow header="Записей">
|
||||
555
|
||||
</InfoRow>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<InfoRow header="Рейтинг">
|
||||
3535
|
||||
</InfoRow>
|
||||
</Cell>
|
||||
</List>
|
||||
</ModalPage>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withPlatform(connect()(HomeBotsListModal));
|
||||
74
src/js/components/modals/HomeBotsListModal.js
Normal file
74
src/js/components/modals/HomeBotsListModal.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {openModal} from "../../store/router/actions";
|
||||
|
||||
import {List, Cell, Avatar, ModalPage, ModalPageHeader, PanelHeaderButton, withPlatform, IOS} from "@vkontakte/vkui";
|
||||
|
||||
import Icon24Dismiss from '@vkontakte/icons/dist/24/dismiss';
|
||||
import Icon24Cancel from '@vkontakte/icons/dist/24/cancel';
|
||||
import Icon24Chevron from '@vkontakte/icons/dist/24/chevron';
|
||||
|
||||
const bots = [
|
||||
{
|
||||
name: 'VKS',
|
||||
avatar: 'https://pp.userapi.com/c851520/v851520442/48ce/Sik7V4c58qw.jpg',
|
||||
desc: 'Нет, меня не роняли в детстве'
|
||||
},
|
||||
{
|
||||
name: 'Недобот',
|
||||
avatar: 'https://pp.userapi.com/c854420/v854420431/da51/X8ohw4-4Fk4.jpg',
|
||||
desc: 'Я ни разу не пил кокосовое молоко'
|
||||
},
|
||||
{
|
||||
name: 'Realm of War',
|
||||
avatar: 'https://sun9-72.userapi.com/c853520/v853520591/1f167d/avj_z9yFtQA.jpg?ava=1',
|
||||
desc: 'Ненавижу спойлеры.'
|
||||
},
|
||||
];
|
||||
|
||||
class HomeBotsListModal extends React.Component {
|
||||
|
||||
render() {
|
||||
const {id, onClose, openModal, platform} = this.props;
|
||||
|
||||
return (
|
||||
<ModalPage
|
||||
id={id}
|
||||
header={
|
||||
<ModalPageHeader
|
||||
left={platform !== IOS &&
|
||||
<PanelHeaderButton onClick={onClose}><Icon24Cancel/></PanelHeaderButton>}
|
||||
right={platform === IOS &&
|
||||
<PanelHeaderButton onClick={onClose}><Icon24Dismiss/></PanelHeaderButton>}
|
||||
>
|
||||
/appbots на минималках
|
||||
</ModalPageHeader>
|
||||
}
|
||||
onClose={onClose}
|
||||
settlingHeight={80}
|
||||
>
|
||||
<List>
|
||||
{bots.map((bot, index) => (
|
||||
<Cell
|
||||
key={index}
|
||||
description={bot.desc}
|
||||
before={<Avatar size={40} src={bot.avatar}/>}
|
||||
onClick={() => openModal('MODAL_PAGE_BOT_INFO')}
|
||||
asideContent={<Icon24Chevron fill="#528bcc"/>}
|
||||
>
|
||||
{bot.name}
|
||||
</Cell>
|
||||
))}
|
||||
</List>
|
||||
</ModalPage>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
openModal
|
||||
};
|
||||
|
||||
export default withPlatform(connect(null, mapDispatchToProps)(HomeBotsListModal));
|
||||
87
src/js/panels/home/base.js
Normal file
87
src/js/panels/home/base.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { closePopout, goBack, openModal, openPopout, setPage } from '../../store/router/actions';
|
||||
|
||||
import { Div, Panel, Alert, Group, Button, PanelHeader } from "@vkontakte/vkui"
|
||||
|
||||
class HomePanelBase extends React.Component {
|
||||
|
||||
state = {
|
||||
showImg: false
|
||||
};
|
||||
|
||||
showImg = () => {
|
||||
this.setState({ showImg: true });
|
||||
};
|
||||
|
||||
openPopout() {
|
||||
this.props.openPopout(
|
||||
<Alert
|
||||
actions={[{
|
||||
title: 'Нет',
|
||||
autoclose: true,
|
||||
style: 'cancel',
|
||||
}, {
|
||||
title: 'Да',
|
||||
autoclose: true,
|
||||
action: this.showImg
|
||||
}]}
|
||||
onClose={() => this.props.closePopout()}
|
||||
>
|
||||
<h2>Вопрос значит</h2>
|
||||
<p>Вас роняли в детстве?</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { id, setPage, withoutEpic } = this.props;
|
||||
const url = new URL(window.location.href);
|
||||
const payload = async () => {
|
||||
if (url.searchParams.get('payload') != null) return await url.searchParams.get('payload');
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Panel id={id}>
|
||||
<PanelHeader>Examples</PanelHeader>
|
||||
<Group>
|
||||
{/* <Div>
|
||||
<Button mode="secondary" size="l" stretched={true} onClick={() => setPage('home', 'groups')}>Список моих
|
||||
групп</Button>
|
||||
</Div> */}
|
||||
<Div>
|
||||
<p>
|
||||
{new URL(window.location.href).searchParams.get('payload') ? ('ваш ник: ' + new URL(window.location.href).searchParams.get('payload')) : 'ВЫ НЕ АВТОРИЗОВАНЫ'}
|
||||
</p>
|
||||
</Div>
|
||||
{/* <Div>
|
||||
<p>{params.get('payload')}</p>
|
||||
</Div> */}
|
||||
<Div>
|
||||
<Button mode="secondary" size="l" stretched={true} onClick={() => this.openPopout()}>Открыть алерт</Button>
|
||||
</Div>
|
||||
<Div>
|
||||
<Button mode="secondary" size="l" stretched={true} onClick={() => this.props.openModal("MODAL_PAGE_BOTS_LIST")}>Открыть
|
||||
модальную страницу</Button>
|
||||
</Div>
|
||||
|
||||
</Group>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setPage,
|
||||
goBack,
|
||||
openPopout,
|
||||
closePopout,
|
||||
openModal
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(HomePanelBase);
|
||||
145
src/js/panels/home/groups.js
Normal file
145
src/js/panels/home/groups.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from "redux";
|
||||
|
||||
import {goBack, openPopout, closePopout, openModal} from "../../store/router/actions";
|
||||
import * as VK from '../../services/VK';
|
||||
|
||||
import {renderGroupsList} from '../../services/renderers';
|
||||
|
||||
import {Div, List, Panel, Group, Button, PanelHeader, PanelSpinner, PanelHeaderBack, Header} from "@vkontakte/vkui";
|
||||
|
||||
class HomePanelGroups extends React.Component {
|
||||
|
||||
state = {
|
||||
groups: {
|
||||
admined: [],
|
||||
other: [],
|
||||
},
|
||||
loading: true,
|
||||
errorGetAuthToken: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.accessToken === undefined) {
|
||||
this.getAuthToken();
|
||||
} else {
|
||||
this.getGroupsList();
|
||||
}
|
||||
}
|
||||
|
||||
getAuthToken() {
|
||||
this.props.dispatch(VK.getAuthToken(['groups']));
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (this.props !== prevProps) {
|
||||
if (this.props.accessToken === null) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
errorGetAuthToken: true
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
loading: true,
|
||||
errorGetAuthToken: false
|
||||
});
|
||||
|
||||
this.getGroupsList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getGroupsList() {
|
||||
if (localStorage.getItem('userGroupsAdmined') && localStorage.getItem('userGroupsOther')) {
|
||||
this.setState({
|
||||
groups: {
|
||||
admined: JSON.parse(localStorage.getItem('userGroupsAdmined')),
|
||||
other: JSON.parse(localStorage.getItem('userGroupsOther')),
|
||||
},
|
||||
loading: false
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let groups = await VK.groupsGet();
|
||||
console.log(groups);
|
||||
|
||||
let adminedGroups = groups.items.filter(function (item) {
|
||||
return item.is_admin === 1;
|
||||
});
|
||||
|
||||
let otherGroups = groups.items.filter(function (item) {
|
||||
return item.is_admin === 0;
|
||||
});
|
||||
|
||||
localStorage.setItem('userGroupsAdmined', JSON.stringify(adminedGroups));
|
||||
localStorage.setItem('userGroupsOther', JSON.stringify(otherGroups));
|
||||
|
||||
this.setState({
|
||||
groups: {
|
||||
admined: adminedGroups,
|
||||
other: otherGroups
|
||||
},
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {id, goBack} = this.props;
|
||||
|
||||
let adminedGroupsList = renderGroupsList(this.state.groups.admined);
|
||||
let otherGroupsList = renderGroupsList(this.state.groups.other);
|
||||
|
||||
return (
|
||||
<Panel id={id}>
|
||||
<PanelHeader
|
||||
left={<PanelHeaderBack onClick={() => goBack()}/>}
|
||||
>
|
||||
Группы
|
||||
</PanelHeader>
|
||||
{this.state.loading && <PanelSpinner/>}
|
||||
{!this.state.loading && this.state.errorGetAuthToken && <Group>
|
||||
<Div>Возникла ошибка при получении данных, возможно Вы не выдали права на список групп.</Div>
|
||||
<Div>
|
||||
<Button size="l" stretched={true} onClick={() => this.getAuthToken()}>Запросить
|
||||
повторно</Button>
|
||||
</Div>
|
||||
</Group>}
|
||||
{!this.state.loading && !this.state.errorGetAuthToken && adminedGroupsList &&
|
||||
<Group header={
|
||||
<Header mode="secondary">Администрируемые</Header>
|
||||
}>
|
||||
<List>
|
||||
{adminedGroupsList}
|
||||
</List>
|
||||
</Group>}
|
||||
{!this.state.loading && !this.state.errorGetAuthToken && otherGroupsList &&
|
||||
<Group header={
|
||||
<Header mode="secondary">Остальные</Header>
|
||||
}>
|
||||
<List>
|
||||
{otherGroupsList}
|
||||
</List>
|
||||
</Group>}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
dispatch,
|
||||
...bindActionCreators({goBack, openPopout, closePopout, openModal}, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
accessToken: state.vkui.accessToken
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomePanelGroups);
|
||||
109
src/js/panels/more/base.js
Normal file
109
src/js/panels/more/base.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {setPage} from "../../store/router/actions";
|
||||
import {setActiveTab, setScrollPositionByID} from "../../store/vk/actions";
|
||||
import {restoreScrollPosition} from "../../services/_functions";
|
||||
|
||||
import {
|
||||
Div,
|
||||
Panel,
|
||||
Group,
|
||||
CellButton,
|
||||
PanelHeader,
|
||||
FixedLayout,
|
||||
HorizontalScroll,
|
||||
TabsItem,
|
||||
Tabs
|
||||
} from "@vkontakte/vkui";
|
||||
|
||||
class HomePanelProfile extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
activeTab: props.activeTab["EXAMPLE"] || "modal"
|
||||
};
|
||||
}
|
||||
|
||||
setTab(tab) {
|
||||
this.setState({
|
||||
activeTab: tab
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const {setScrollPositionByID, setActiveTab} = this.props;
|
||||
|
||||
setActiveTab("EXAMPLE", this.state.activeTab);
|
||||
setScrollPositionByID("EXAMPLE_TABS_LIST");
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
restoreScrollPosition();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {id, setPage} = this.props;
|
||||
const boxStyle = {marginTop: 56};
|
||||
|
||||
return (
|
||||
<Panel id={id}>
|
||||
<PanelHeader noShadow={true}>Examples 2</PanelHeader>
|
||||
<FixedLayout vertical="top">
|
||||
<Tabs theme="header" mode="default">
|
||||
<HorizontalScroll id="EXAMPLE_TABS_LIST">
|
||||
<TabsItem
|
||||
onClick={() => this.setTab('modal')}
|
||||
selected={this.state.activeTab === 'modal'}
|
||||
>
|
||||
Модальное окно
|
||||
</TabsItem>
|
||||
<TabsItem
|
||||
onClick={() => this.setTab('test')}
|
||||
selected={this.state.activeTab === 'test'}
|
||||
>
|
||||
Для теста
|
||||
</TabsItem>
|
||||
<TabsItem
|
||||
onClick={() => this.setTab('test2')}
|
||||
selected={this.state.activeTab === 'test2'}
|
||||
>
|
||||
Для теста 2
|
||||
</TabsItem>
|
||||
<TabsItem
|
||||
onClick={() => this.setTab('test3')}
|
||||
selected={this.state.activeTab === 'test3'}
|
||||
>
|
||||
Для теста 3
|
||||
</TabsItem>
|
||||
</HorizontalScroll>
|
||||
</Tabs>
|
||||
</FixedLayout>
|
||||
<Group style={boxStyle}>
|
||||
{this.state.activeTab === 'modal' && <CellButton onClick={() => setPage('modal', 'filters')}>
|
||||
Открыть модальное окно
|
||||
</CellButton>}
|
||||
|
||||
{this.state.activeTab !== 'modal' && <Div>{this.state.activeTab}</Div>}
|
||||
</Group>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
activeTab: state.vkui.activeTab,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setPage,
|
||||
setActiveTab,
|
||||
setScrollPositionByID
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomePanelProfile);
|
||||
120
src/js/panels/more/example.js
Normal file
120
src/js/panels/more/example.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {goBack} from '../../store/router/actions';
|
||||
import {setFormData} from "../../store/formData/actions";
|
||||
|
||||
import {
|
||||
Div,
|
||||
Button,
|
||||
Checkbox,
|
||||
Input,
|
||||
FormLayout,
|
||||
FormLayoutGroup,
|
||||
Panel,
|
||||
Group,
|
||||
PanelHeader,
|
||||
PanelHeaderBack
|
||||
} from "@vkontakte/vkui";
|
||||
|
||||
class HomePanelProfile extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let defaultInputData = {
|
||||
workplace: '',
|
||||
workposition: '',
|
||||
|
||||
checkboxPhoto: 0,
|
||||
checkboxOnline: 0
|
||||
};
|
||||
|
||||
this.state = {
|
||||
inputData: props.inputData['example_form'] || defaultInputData
|
||||
};
|
||||
|
||||
this.handleInput = (e) => {
|
||||
let value = e.currentTarget.value;
|
||||
|
||||
if (e.currentTarget.type === 'checkbox') {
|
||||
value = e.currentTarget.checked;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
inputData: {
|
||||
...this.state.inputData,
|
||||
[e.currentTarget.name]: value
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.clearForm = () => {
|
||||
this.setState({
|
||||
inputData: defaultInputData
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.setFormData('example_form', this.state.inputData);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {id, goBack} = this.props;
|
||||
|
||||
return (
|
||||
<Panel id={id}>
|
||||
<PanelHeader
|
||||
left={<PanelHeaderBack onClick={() => goBack()}/>}
|
||||
>
|
||||
Модальное окно
|
||||
</PanelHeader>
|
||||
<Group>
|
||||
<FormLayout>
|
||||
<FormLayoutGroup top="Работа">
|
||||
<Input value={this.state.inputData.workplace}
|
||||
onChange={this.handleInput}
|
||||
name="workplace"
|
||||
placeholder="Место работы"
|
||||
autoComplete="off"/>
|
||||
<Input value={this.state.inputData.workposition}
|
||||
onChange={this.handleInput}
|
||||
name="workposition"
|
||||
placeholder="Должность"
|
||||
autoComplete="off"/>
|
||||
</FormLayoutGroup>
|
||||
<FormLayoutGroup top="Дополнительно">
|
||||
<Checkbox checked={this.state.inputData.checkboxPhoto}
|
||||
onChange={this.handleInput}
|
||||
name="checkboxPhoto"
|
||||
>С фотографией</Checkbox>
|
||||
<Checkbox checked={this.state.inputData.checkboxOnline}
|
||||
onChange={this.handleInput}
|
||||
name="checkboxOnline"
|
||||
>Сейчас на сайте</Checkbox>
|
||||
</FormLayoutGroup>
|
||||
</FormLayout>
|
||||
<Div className="buttons-group">
|
||||
<Button size="l" stretched={true} onClick={() => goBack()}>Сохранить</Button>
|
||||
<Button size="l" stretched={true} onClick={this.clearForm}>Очистить</Button>
|
||||
</Div>
|
||||
</Group>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
inputData: state.formData.forms,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setFormData,
|
||||
goBack
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomePanelProfile);
|
||||
84
src/js/services/VK.js
Normal file
84
src/js/services/VK.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import VKConnect from "@vkontakte/vk-connect";
|
||||
|
||||
import {store} from "../../index";
|
||||
|
||||
import {setColorScheme, setAccessToken} from "../store/vk/actions";
|
||||
|
||||
const APP_ID = 6984089;
|
||||
const API_VERSION = '5.92';
|
||||
|
||||
export const initApp = () => (dispatch) => {
|
||||
const VKConnectCallback = (e) => {
|
||||
if (e.detail.type === 'VKWebAppUpdateConfig') {
|
||||
VKConnect.unsubscribe(VKConnectCallback);
|
||||
|
||||
dispatch(setColorScheme(e.detail.data.scheme));
|
||||
}
|
||||
};
|
||||
|
||||
VKConnect.subscribe(VKConnectCallback);
|
||||
return VKConnect.send('VKWebAppInit', {}).then(data => {
|
||||
return data;
|
||||
}).catch(error => {
|
||||
return error;
|
||||
});
|
||||
};
|
||||
|
||||
export const getAuthToken = (scope) => (dispatch) => {
|
||||
VKConnect.send("VKWebAppGetAuthToken", {
|
||||
"app_id": APP_ID,
|
||||
"scope": scope.join(',')
|
||||
}).then(data => {
|
||||
dispatch(setAccessToken(data.access_token));
|
||||
}).catch(() => {
|
||||
dispatch(setAccessToken(null));
|
||||
});
|
||||
};
|
||||
|
||||
export const closeApp = () => {
|
||||
return VKConnect.send("VKWebAppClose", {
|
||||
"status": "success"
|
||||
}).then(data => {
|
||||
return data;
|
||||
}).catch(error => {
|
||||
return error;
|
||||
});
|
||||
};
|
||||
|
||||
export const swipeBackOn = () => {
|
||||
return VKConnect.send("VKWebAppEnableSwipeBack", {}).then(data => {
|
||||
return data;
|
||||
}).catch(error => {
|
||||
return error;
|
||||
});
|
||||
};
|
||||
|
||||
export const swipeBackOff = () => {
|
||||
return VKConnect.send("VKWebAppDisableSwipeBack", {}).then(data => {
|
||||
return data;
|
||||
}).catch(error => {
|
||||
return error;
|
||||
});
|
||||
};
|
||||
|
||||
export const groupsGet = () => {
|
||||
return APICall('groups.get', {
|
||||
"extended": "1",
|
||||
"fields": "description",
|
||||
"count": "100"
|
||||
});
|
||||
};
|
||||
|
||||
export const APICall = (method, params) => {
|
||||
params['access_token'] = store.getState().vkui.accessToken;
|
||||
params['v'] = params['v'] === undefined ? API_VERSION : params['v'];
|
||||
|
||||
return VKConnect.send("VKWebAppCallAPIMethod", {
|
||||
"method": method,
|
||||
"params": params
|
||||
}).then(data => {
|
||||
return data.response;
|
||||
}).catch(error => {
|
||||
return error;
|
||||
});
|
||||
};
|
||||
42
src/js/services/_functions.js
Normal file
42
src/js/services/_functions.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import {store} from "../../index";
|
||||
|
||||
export const smoothScrollToTop = () => {
|
||||
const c = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
|
||||
if (c > 30) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c > 0) {
|
||||
window.requestAnimationFrame(smoothScrollToTop);
|
||||
window.scrollTo(0, c - c / 8);
|
||||
}
|
||||
};
|
||||
|
||||
export const restoreScrollPosition = () => {
|
||||
let scrolls = store.getState().vkui.componentScroll;
|
||||
|
||||
Object.keys(scrolls).forEach((component) => {
|
||||
let componentData = scrolls[component];
|
||||
|
||||
let element = document.getElementById(component);
|
||||
|
||||
if (element) {
|
||||
element = element.getElementsByClassName("HorizontalScroll__in")[0];
|
||||
|
||||
element.scrollLeft = componentData.x;
|
||||
element.scrollTop = componentData.y;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const getActivePanel = (view) => {
|
||||
let panel = store.getState().router.activePanel;
|
||||
|
||||
let panelsHistory = store.getState().router.panelsHistory;
|
||||
if (typeof panelsHistory[view] !== "undefined") {
|
||||
panel = panelsHistory[view][panelsHistory[view].length - 1];
|
||||
}
|
||||
|
||||
return panel;
|
||||
};
|
||||
16
src/js/services/renderers.js
Normal file
16
src/js/services/renderers.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import GroupCell from '../components/GroupCell';
|
||||
|
||||
export const renderGroupsList = (items) => {
|
||||
let groups = null;
|
||||
if (items !== undefined && items !== null && items.length !== 0) {
|
||||
groups = items.map((group) => (
|
||||
<GroupCell
|
||||
key={group.id}
|
||||
description={group.description}
|
||||
photo={group.photo_100}
|
||||
name={group.name}/>
|
||||
));
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
1
src/js/store/formData/actionTypes.js
Normal file
1
src/js/store/formData/actionTypes.js
Normal file
@@ -0,0 +1 @@
|
||||
export const SET_FORM_DATA = 'SAVE_FORM_DATA';
|
||||
11
src/js/store/formData/actions.js
Normal file
11
src/js/store/formData/actions.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import {SET_FORM_DATA} from './actionTypes';
|
||||
|
||||
export const setFormData = (formName, inputData) => (
|
||||
{
|
||||
type: SET_FORM_DATA,
|
||||
payload: {
|
||||
form: formName,
|
||||
data: inputData,
|
||||
}
|
||||
}
|
||||
);
|
||||
27
src/js/store/formData/reducers.js
Normal file
27
src/js/store/formData/reducers.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import {SET_FORM_DATA} from './actionTypes';
|
||||
|
||||
const initialState = {
|
||||
forms: []
|
||||
};
|
||||
|
||||
export const formDataReducer = (state = initialState, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case SET_FORM_DATA: {
|
||||
return {
|
||||
...state,
|
||||
forms: {
|
||||
...state.forms,
|
||||
[action.payload.form]: action.payload.data
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
10
src/js/store/reducers.js
Normal file
10
src/js/store/reducers.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import {combineReducers} from "redux";
|
||||
import {routerReducer} from './router/reducers';
|
||||
import {vkuiReducer} from './vk/reducers';
|
||||
import {formDataReducer} from "./formData/reducers";
|
||||
|
||||
export default combineReducers({
|
||||
vkui: vkuiReducer,
|
||||
router: routerReducer,
|
||||
formData: formDataReducer
|
||||
});
|
||||
7
src/js/store/router/actionTypes.js
Normal file
7
src/js/store/router/actionTypes.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const SET_PAGE = 'SET_PAGE';
|
||||
export const SET_STORY = 'SET_STORY';
|
||||
export const GO_BACK = 'GO_BACK';
|
||||
export const OPEN_POPOUT = 'OPEN_POPOUT';
|
||||
export const CLOSE_POPOUT = 'CLOSE_POPOUT';
|
||||
export const OPEN_MODAL = 'OPEN_MODAL';
|
||||
export const CLOSE_MODAL = 'CLOSE_MODAL';
|
||||
57
src/js/store/router/actions.js
Normal file
57
src/js/store/router/actions.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import {SET_PAGE, SET_STORY, GO_BACK, OPEN_POPOUT, CLOSE_POPOUT, OPEN_MODAL, CLOSE_MODAL} from './actionTypes';
|
||||
|
||||
export const setStory = (story, initial_panel) => (
|
||||
{
|
||||
type: SET_STORY,
|
||||
payload: {
|
||||
story: story,
|
||||
initial_panel: initial_panel,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const setPage = (view, panel) => (
|
||||
{
|
||||
type: SET_PAGE,
|
||||
payload: {
|
||||
view: view,
|
||||
panel: panel
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const goBack = () => (
|
||||
{
|
||||
type: GO_BACK
|
||||
}
|
||||
);
|
||||
|
||||
export const openPopout = (popout) => (
|
||||
{
|
||||
type: OPEN_POPOUT,
|
||||
payload: {
|
||||
popout: popout
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const closePopout = () => (
|
||||
{
|
||||
type: CLOSE_POPOUT
|
||||
}
|
||||
);
|
||||
|
||||
export const openModal = (id) => (
|
||||
{
|
||||
type: OPEN_MODAL,
|
||||
payload: {
|
||||
id
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const closeModal = () => (
|
||||
{
|
||||
type: CLOSE_MODAL
|
||||
}
|
||||
);
|
||||
313
src/js/store/router/reducers.js
Normal file
313
src/js/store/router/reducers.js
Normal file
@@ -0,0 +1,313 @@
|
||||
import {
|
||||
SET_PAGE,
|
||||
GO_BACK,
|
||||
OPEN_POPOUT,
|
||||
CLOSE_POPOUT,
|
||||
OPEN_MODAL,
|
||||
CLOSE_MODAL,
|
||||
SET_STORY
|
||||
} from './actionTypes';
|
||||
|
||||
import * as VK from "../../services/VK";
|
||||
import {smoothScrollToTop} from "../../services/_functions";
|
||||
|
||||
const initialState = {
|
||||
activeStory: null,
|
||||
activeView: null,
|
||||
activePanel: null,
|
||||
|
||||
storiesHistory: [],
|
||||
viewsHistory: [],
|
||||
panelsHistory: [],
|
||||
|
||||
activeModals: [],
|
||||
modalHistory: [],
|
||||
popouts: [],
|
||||
|
||||
scrollPosition: []
|
||||
};
|
||||
|
||||
export const routerReducer = (state = initialState, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case SET_PAGE: {
|
||||
let View = action.payload.view;
|
||||
let Panel = action.payload.panel;
|
||||
|
||||
window.history.pushState(null, null);
|
||||
|
||||
let panelsHistory = state.panelsHistory[View] || [];
|
||||
let viewsHistory = state.viewsHistory[state.activeStory] || [];
|
||||
|
||||
const viewIndexInHistory = viewsHistory.indexOf(View);
|
||||
|
||||
if (viewIndexInHistory !== -1) {
|
||||
viewsHistory.splice(viewIndexInHistory, 1);
|
||||
}
|
||||
|
||||
if (panelsHistory.indexOf(Panel) === -1) {
|
||||
panelsHistory = [...panelsHistory, Panel];
|
||||
}
|
||||
|
||||
if (panelsHistory.length > 1) {
|
||||
VK.swipeBackOn();
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeView: View,
|
||||
activePanel: Panel,
|
||||
|
||||
panelsHistory: {
|
||||
...state.panelsHistory,
|
||||
[View]: panelsHistory,
|
||||
},
|
||||
viewsHistory: {
|
||||
...state.viewsHistory,
|
||||
[state.activeStory]: [...viewsHistory, View]
|
||||
},
|
||||
scrollPosition: {
|
||||
...state.scrollPosition,
|
||||
[state.activeStory + "_" + state.activeView + "_" + state.activePanel]: window.pageYOffset
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_STORY: {
|
||||
window.history.pushState(null, null);
|
||||
|
||||
let viewsHistory = state.viewsHistory[action.payload.story] || [action.payload.story];
|
||||
|
||||
let storiesHistory = state.storiesHistory;
|
||||
let activeView = viewsHistory[viewsHistory.length - 1];
|
||||
let panelsHistory = state.panelsHistory[activeView] || [action.payload.initial_panel];
|
||||
let activePanel = panelsHistory[panelsHistory.length - 1];
|
||||
|
||||
if (action.payload.story === state.activeStory) {
|
||||
if (panelsHistory.length > 1) {
|
||||
let firstPanel = panelsHistory.shift();
|
||||
panelsHistory = [firstPanel];
|
||||
|
||||
activePanel = panelsHistory[panelsHistory.length - 1];
|
||||
} else if (viewsHistory.length > 1) {
|
||||
let firstView = viewsHistory.shift();
|
||||
viewsHistory = [firstView];
|
||||
|
||||
activeView = viewsHistory[viewsHistory.length - 1];
|
||||
panelsHistory = state.panelsHistory[activeView];
|
||||
activePanel = panelsHistory[panelsHistory.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (action.payload.story === state.activeStory && panelsHistory.length === 1 && window.pageYOffset > 0) {
|
||||
window.scrollTo(0, 30);
|
||||
|
||||
smoothScrollToTop();
|
||||
}
|
||||
|
||||
const storiesIndexInHistory = storiesHistory.indexOf(action.payload.story);
|
||||
|
||||
if (storiesIndexInHistory === -1 || (storiesHistory[0] === action.payload.story && storiesHistory[storiesHistory.length - 1] !== action.payload.story)) {
|
||||
storiesHistory = [...storiesHistory, action.payload.story];
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeStory: action.payload.story,
|
||||
activeView: activeView,
|
||||
activePanel: activePanel,
|
||||
|
||||
storiesHistory: storiesHistory,
|
||||
viewsHistory: {
|
||||
...state.viewsHistory,
|
||||
[activeView]: viewsHistory
|
||||
},
|
||||
panelsHistory: {
|
||||
...state.panelsHistory,
|
||||
[activeView]: panelsHistory
|
||||
},
|
||||
|
||||
scrollPosition: {
|
||||
...state.scrollPosition,
|
||||
[state.activeStory + "_" + state.activeView + "_" + state.activePanel]: window.pageYOffset
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case GO_BACK: {
|
||||
let setView = state.activeView;
|
||||
let setPanel = state.activePanel;
|
||||
let setStory = state.activeStory;
|
||||
|
||||
let popoutsData = state.popouts;
|
||||
|
||||
if (popoutsData[setView]) {
|
||||
popoutsData[setView] = null;
|
||||
|
||||
return {
|
||||
...state,
|
||||
popouts: {
|
||||
...state.popouts, popoutsData
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let viewModalsHistory = state.modalHistory[setView];
|
||||
|
||||
if (viewModalsHistory !== undefined && viewModalsHistory.length !== 0) {
|
||||
let activeModal = viewModalsHistory[viewModalsHistory.length - 2] || null;
|
||||
|
||||
if (activeModal === null) {
|
||||
viewModalsHistory = [];
|
||||
} else if (viewModalsHistory.indexOf(activeModal) !== -1) {
|
||||
viewModalsHistory = viewModalsHistory.splice(0, viewModalsHistory.indexOf(activeModal) + 1);
|
||||
} else {
|
||||
viewModalsHistory.push(activeModal);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeModals: {
|
||||
...state.activeModals,
|
||||
[setView]: activeModal
|
||||
},
|
||||
modalHistory: {
|
||||
...state.modalHistory,
|
||||
[setView]: viewModalsHistory
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let panelsHistory = state.panelsHistory[setView] || [];
|
||||
let viewsHistory = state.viewsHistory[state.activeStory] || [];
|
||||
let storiesHistory = state.storiesHistory;
|
||||
|
||||
if (panelsHistory.length > 1) {
|
||||
panelsHistory.pop();
|
||||
|
||||
setPanel = panelsHistory[panelsHistory.length - 1];
|
||||
} else if (viewsHistory.length > 1) {
|
||||
viewsHistory.pop();
|
||||
|
||||
setView = viewsHistory[viewsHistory.length - 1];
|
||||
let panelsHistoryNew = state.panelsHistory[setView];
|
||||
|
||||
setPanel = panelsHistoryNew[panelsHistoryNew.length - 1];
|
||||
} else if (storiesHistory.length > 1) {
|
||||
storiesHistory.pop();
|
||||
|
||||
setStory = storiesHistory[storiesHistory.length - 1];
|
||||
setView = state.viewsHistory[setStory][state.viewsHistory[setStory].length - 1];
|
||||
|
||||
let panelsHistoryNew = state.panelsHistory[setView];
|
||||
|
||||
if (panelsHistoryNew.length > 1) {
|
||||
setPanel = panelsHistoryNew[panelsHistoryNew.length - 1];
|
||||
} else {
|
||||
setPanel = panelsHistoryNew[0];
|
||||
}
|
||||
} else {
|
||||
VK.closeApp();
|
||||
}
|
||||
|
||||
if (panelsHistory.length === 1) {
|
||||
VK.swipeBackOff();
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeView: setView,
|
||||
activePanel: setPanel,
|
||||
activeStory: setStory,
|
||||
|
||||
viewsHistory: {
|
||||
...state.viewsHistory,
|
||||
[state.activeView]: viewsHistory
|
||||
},
|
||||
panelsHistory: {
|
||||
...state.panelsHistory,
|
||||
[state.activeView]: panelsHistory
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case OPEN_POPOUT: {
|
||||
window.history.pushState(null, null);
|
||||
|
||||
return {
|
||||
...state,
|
||||
popouts: {
|
||||
...state.popouts,
|
||||
[state.activeView]: action.payload.popout
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case CLOSE_POPOUT: {
|
||||
return {
|
||||
...state,
|
||||
popouts: {
|
||||
...state.popouts,
|
||||
[state.activeView]: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case OPEN_MODAL: {
|
||||
window.history.pushState(null, null);
|
||||
|
||||
let activeModal = action.payload.id || null;
|
||||
let modalsHistory = state.modalHistory[state.activeView] ? [...state.modalHistory[state.activeView]] : [];
|
||||
|
||||
if (activeModal === null) {
|
||||
modalsHistory = [];
|
||||
} else if (modalsHistory.indexOf(activeModal) !== -1) {
|
||||
modalsHistory = modalsHistory.splice(0, modalsHistory.indexOf(activeModal) + 1);
|
||||
} else {
|
||||
modalsHistory.push(activeModal);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeModals: {
|
||||
...state.activeModals,
|
||||
[state.activeView]: activeModal
|
||||
},
|
||||
modalHistory: {
|
||||
...state.modalHistory,
|
||||
[state.activeView]: modalsHistory
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case CLOSE_MODAL: {
|
||||
let activeModal = state.modalHistory[state.activeView][state.modalHistory[state.activeView].length - 2] || null;
|
||||
let modalsHistory = state.modalHistory[state.activeView] ? [...state.modalHistory[state.activeView]] : [];
|
||||
|
||||
if (activeModal === null) {
|
||||
modalsHistory = [];
|
||||
} else if (modalsHistory.indexOf(activeModal) !== -1) {
|
||||
modalsHistory = modalsHistory.splice(0, modalsHistory.indexOf(activeModal) + 1);
|
||||
} else {
|
||||
modalsHistory.push(activeModal);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeModals: {
|
||||
...state.activeModals,
|
||||
[state.activeView]: activeModal
|
||||
},
|
||||
modalHistory: {
|
||||
...state.modalHistory,
|
||||
[state.activeView]: modalsHistory
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
5
src/js/store/vk/actionTypes.js
Normal file
5
src/js/store/vk/actionTypes.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export const SET_COLOR_SCHEME = 'SET_COLOR_SCHEME';
|
||||
export const SET_ACCESS_TOKEN = 'SET_ACCESS_TOKEN';
|
||||
export const SET_ACTIVE_TAB = 'SET_ACTIVE_TAB';
|
||||
export const SET_SCROLL_POSITION = 'SET_SCROLL_POSITION';
|
||||
export const SET_SCROLL_POSITION_BY_ID = 'SET_SCROLL_POSITION_BY_ID';
|
||||
51
src/js/store/vk/actions.js
Normal file
51
src/js/store/vk/actions.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
SET_COLOR_SCHEME,
|
||||
SET_ACCESS_TOKEN,
|
||||
SET_ACTIVE_TAB,
|
||||
SET_SCROLL_POSITION,
|
||||
SET_SCROLL_POSITION_BY_ID
|
||||
} from './actionTypes';
|
||||
|
||||
export const setColorScheme = (scheme) => (
|
||||
{
|
||||
type: SET_COLOR_SCHEME,
|
||||
payload: scheme
|
||||
}
|
||||
);
|
||||
|
||||
export const setAccessToken = (accessToken) => (
|
||||
{
|
||||
type: SET_ACCESS_TOKEN,
|
||||
payload: accessToken
|
||||
}
|
||||
);
|
||||
|
||||
export const setActiveTab = (component, tab) => (
|
||||
{
|
||||
type: SET_ACTIVE_TAB,
|
||||
payload: {
|
||||
component,
|
||||
tab
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const setScrollPosition = (component, x = 0, y = 0) => (
|
||||
{
|
||||
type: SET_SCROLL_POSITION,
|
||||
payload: {
|
||||
component,
|
||||
x,
|
||||
y
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const setScrollPositionByID = (component) => (
|
||||
{
|
||||
type: SET_SCROLL_POSITION_BY_ID,
|
||||
payload: {
|
||||
component
|
||||
}
|
||||
}
|
||||
);
|
||||
80
src/js/store/vk/reducers.js
Normal file
80
src/js/store/vk/reducers.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
SET_ACCESS_TOKEN,
|
||||
SET_ACTIVE_TAB,
|
||||
SET_COLOR_SCHEME,
|
||||
SET_SCROLL_POSITION,
|
||||
SET_SCROLL_POSITION_BY_ID
|
||||
} from './actionTypes';
|
||||
|
||||
const initialState = {
|
||||
accessToken: undefined,
|
||||
colorScheme: 'client_light',
|
||||
|
||||
activeTab: [],
|
||||
componentScroll: []
|
||||
};
|
||||
|
||||
export const vkuiReducer = (state = initialState, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case SET_COLOR_SCHEME: {
|
||||
return {
|
||||
...state,
|
||||
colorScheme: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
case SET_ACCESS_TOKEN: {
|
||||
return {
|
||||
...state,
|
||||
accessToken: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
case SET_ACTIVE_TAB: {
|
||||
return {
|
||||
...state,
|
||||
activeTab: {
|
||||
...state.activeTab,
|
||||
[action.payload.component]: action.payload.tab
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case SET_SCROLL_POSITION: {
|
||||
return {
|
||||
...state,
|
||||
componentScroll: {
|
||||
...state.componentScroll,
|
||||
[action.payload.component]: {
|
||||
x: action.payload.x,
|
||||
y: action.payload.y
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case SET_SCROLL_POSITION_BY_ID: {
|
||||
let element = document.getElementById(action.payload.component).getElementsByClassName("HorizontalScroll__in")[0];
|
||||
|
||||
let x = element.scrollLeft;
|
||||
let y = element.scrollTop;
|
||||
|
||||
return {
|
||||
...state,
|
||||
componentScroll: {
|
||||
...state.componentScroll,
|
||||
[action.payload.component]: {
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user