Разработана архитектура и несколько компонентов веб-интерфейса
Этот коммит содержится в:
родитель
51e4174ad2
Коммит
1e22d40d19
@ -1,17 +0,0 @@
|
|||||||
#root {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: 0;
|
|
||||||
background-color: var(--md-sys-color-surface-container-high);
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
main > * {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import React, { useEffect } from 'react'
|
|
||||||
import { styles as typescaleStyles } from '@material/web/typography/md-typescale-styles.js'
|
|
||||||
|
|
||||||
import PollList from "./PollList";
|
|
||||||
|
|
||||||
import './App.css'
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
useEffect(() => {
|
|
||||||
document.adoptedStyleSheets = [typescaleStyles.styleSheet]
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main className="App">
|
|
||||||
<md-outlined-text-field id="text" label="Favorite color"></md-outlined-text-field>
|
|
||||||
<PollList />
|
|
||||||
</main>
|
|
||||||
// <div className="App">
|
|
||||||
// <header className="App-header">
|
|
||||||
// <img src={logo} className="App-logo" alt="logo"/>
|
|
||||||
// <p>
|
|
||||||
// Edit <code>src/App.js</code> and save to reload.
|
|
||||||
// </p>
|
|
||||||
// <a
|
|
||||||
// className="App-link"
|
|
||||||
// href="https://reactjs.org"
|
|
||||||
// target="_blank"
|
|
||||||
// rel="noopener noreferrer"
|
|
||||||
// >
|
|
||||||
// Learn React
|
|
||||||
// </a>
|
|
||||||
// </header>
|
|
||||||
// </div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
@ -1,45 +0,0 @@
|
|||||||
.full-screen-dialog {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: var(--md-sys-color-surface-container);
|
|
||||||
z-index: 1;
|
|
||||||
animation: .1s show ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-screen-dialog > .top-app-bar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: .5rem;
|
|
||||||
padding: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-screen-dialog > .top-app-bar > * {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-screen-dialog > .top-app-bar > .title {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
color: var(--md-sys-color-on-surface);
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes show {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
scale: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
scale: 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import '@material/web/iconbutton/icon-button.js'
|
|
||||||
import '@material/web/icon/icon.js'
|
|
||||||
import '@material/web/button/filled-button'
|
|
||||||
|
|
||||||
import './FullScreenDialog.css'
|
|
||||||
|
|
||||||
export default function ({
|
|
||||||
editPoll,
|
|
||||||
setEditPoll,
|
|
||||||
}) {
|
|
||||||
// const [close, onClose] = useState(false)
|
|
||||||
return (
|
|
||||||
<div className="full-screen-dialog">
|
|
||||||
<div className="top-app-bar">
|
|
||||||
<md-icon-button onClick={() => setEditPoll(false)}>
|
|
||||||
<md-icon>close</md-icon>
|
|
||||||
</md-icon-button>
|
|
||||||
<div className="title md-typescale-title-large">Изменить опрос</div>
|
|
||||||
<md-filled-button onClick={() => setEditPoll()}>Сохранить</md-filled-button>
|
|
||||||
<md-icon-button>
|
|
||||||
<md-icon>more_vert</md-icon>
|
|
||||||
</md-icon-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.poll-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import PollListItem from "./PollListItem"
|
|
||||||
import FullScreenDialog from "./FullScreenDialog"
|
|
||||||
|
|
||||||
import './PollList.css'
|
|
||||||
|
|
||||||
const PollContext = React.createContext({
|
|
||||||
polls: [],
|
|
||||||
fetchPolls: () => {},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default function PollList() {
|
|
||||||
const [polls, setPolls] = useState([])
|
|
||||||
const [editPoll, setEditPoll] = useState(false)
|
|
||||||
|
|
||||||
const fetchPolls = async () => {
|
|
||||||
const response = await fetch('/api/polls')
|
|
||||||
const polls = await response.json()
|
|
||||||
setPolls(polls)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchPolls()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="poll-list">
|
|
||||||
<PollContext.Provider value={{polls, fetchPolls}}>
|
|
||||||
{polls.map((poll) => (
|
|
||||||
PollListItem(poll, setEditPoll)
|
|
||||||
))}
|
|
||||||
</PollContext.Provider>
|
|
||||||
{editPoll ? <FullScreenDialog editPoll={editPoll} setEditPoll={setEditPoll} /> : null}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import '@material/web/switch/switch.js'
|
|
||||||
|
|
||||||
import './PollListItem.css'
|
|
||||||
|
|
||||||
export default function PollListItem(data, setEditPoll) {
|
|
||||||
return (
|
|
||||||
<div className="poll-list-item" onClick={() => setEditPoll(true)}>
|
|
||||||
<md-ripple></md-ripple>
|
|
||||||
<div>
|
|
||||||
<div className="name md-typescale-title-large">{data.name}</div>
|
|
||||||
<div className="caption md-typescale-body-medium">
|
|
||||||
<span>{data.days_of_week}</span>
|
|
||||||
•
|
|
||||||
<span>{data.time}</span>
|
|
||||||
•
|
|
||||||
<span>{data.question_number}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<md-switch></md-switch>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
3
frontend/src/activities/MainActivity.css
Обычный файл
3
frontend/src/activities/MainActivity.css
Обычный файл
@ -0,0 +1,3 @@
|
|||||||
|
main > * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
35
frontend/src/activities/MainActivity.js
Обычный файл
35
frontend/src/activities/MainActivity.js
Обычный файл
@ -0,0 +1,35 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { styles as typescaleStyles } from '@material/web/typography/md-typescale-styles.js'
|
||||||
|
|
||||||
|
import PollsScreen from '../screens/PollsScreen'
|
||||||
|
import Scaffold from '../components/Scaffold'
|
||||||
|
import NavigationBar from '../components/NavigationBar'
|
||||||
|
|
||||||
|
import './MainActivity.css'
|
||||||
|
|
||||||
|
const bottomBar = (
|
||||||
|
<NavigationBar />
|
||||||
|
)
|
||||||
|
|
||||||
|
const floatingActionButton = (
|
||||||
|
<md-fab id="create-poll-button" label="Создать опрос">
|
||||||
|
<md-icon slot="icon">add</md-icon>
|
||||||
|
</md-fab>
|
||||||
|
)
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<PollsScreen />
|
||||||
|
)
|
||||||
|
|
||||||
|
export default function MainActivity() {
|
||||||
|
useEffect(() => {
|
||||||
|
document.adoptedStyleSheets = [typescaleStyles.styleSheet]
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Scaffold
|
||||||
|
bottomBar={bottomBar}
|
||||||
|
floatingActionButton={floatingActionButton}
|
||||||
|
content={content} />
|
||||||
|
)
|
||||||
|
}
|
36
frontend/src/components/FullScreenDialog.css
Обычный файл
36
frontend/src/components/FullScreenDialog.css
Обычный файл
@ -0,0 +1,36 @@
|
|||||||
|
.full-screen-dialog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
z-index: 2;
|
||||||
|
transition:
|
||||||
|
opacity .1s ease-in-out,
|
||||||
|
scale .1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-dialog.open {
|
||||||
|
opacity: 1;
|
||||||
|
scale: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-dialog.close {
|
||||||
|
opacity: 0;
|
||||||
|
scale: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-dialog > .content {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-dialog > .content > * {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
22
frontend/src/components/FullScreenDialog.js
Обычный файл
22
frontend/src/components/FullScreenDialog.js
Обычный файл
@ -0,0 +1,22 @@
|
|||||||
|
import '@material/web/iconbutton/icon-button.js'
|
||||||
|
import '@material/web/icon/icon.js'
|
||||||
|
import '@material/web/button/filled-button'
|
||||||
|
|
||||||
|
import TopAppBar from './TopAppBar'
|
||||||
|
|
||||||
|
import './FullScreenDialog.css'
|
||||||
|
|
||||||
|
export default function ({
|
||||||
|
setEditPoll,
|
||||||
|
classList,
|
||||||
|
children,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={`full-screen-dialog ${classList}`}>
|
||||||
|
<TopAppBar onDismissRequest={() => setEditPoll(false)} />
|
||||||
|
<div className="content">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
nav {
|
nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: var(--md-sys-color-surface-container);
|
background-color: var(--md-sys-color-surface-container-high);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav ul {
|
nav ul {
|
@ -1,9 +1,9 @@
|
|||||||
import '@material/web/iconbutton/icon-button.js'
|
import '@material/web/iconbutton/icon-button.js'
|
||||||
import '@material/web/icon/icon.js'
|
import '@material/web/icon/icon.js'
|
||||||
|
|
||||||
import './BottomNavBar.css'
|
import './NavigationBar.css'
|
||||||
|
|
||||||
function BottomNavBar() {
|
export default function NavigationBar() {
|
||||||
return (
|
return (
|
||||||
<nav className="md-typescale-body-small">
|
<nav className="md-typescale-body-small">
|
||||||
<ul>
|
<ul>
|
||||||
@ -35,5 +35,3 @@ function BottomNavBar() {
|
|||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BottomNavBar
|
|
@ -3,7 +3,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-list-item .name {
|
.poll-list-item .name {
|
35
frontend/src/components/PollListItem.js
Обычный файл
35
frontend/src/components/PollListItem.js
Обычный файл
@ -0,0 +1,35 @@
|
|||||||
|
import '@material/web/list/list-item'
|
||||||
|
import '@material/web/ripple/ripple'
|
||||||
|
import '@material/web/switch/switch.js'
|
||||||
|
|
||||||
|
import './PollListItem.css'
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function PollListItem(
|
||||||
|
poll,
|
||||||
|
setEditPoll,
|
||||||
|
updatePoll,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<md-list-item onClick={() => setEditPoll(poll)}>
|
||||||
|
<md-ripple></md-ripple>
|
||||||
|
<div className="poll-list-item">
|
||||||
|
<div>
|
||||||
|
<div className="name md-typescale-title-large">{poll.name}</div>
|
||||||
|
<div className="caption md-typescale-body-medium">
|
||||||
|
<span>{poll.daysOfWeek}</span>
|
||||||
|
•
|
||||||
|
<span>{poll.time}</span>
|
||||||
|
•
|
||||||
|
<span>{poll.questionNumber}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<md-switch onClickCapture={(event) => {
|
||||||
|
event.nativeEvent.stopPropagation()
|
||||||
|
poll.isEnabled = !poll.isEnabled
|
||||||
|
updatePoll(poll)
|
||||||
|
}} {...(poll.isEnabled ? {selected: true} : {})}></md-switch>
|
||||||
|
</div>
|
||||||
|
</md-list-item>
|
||||||
|
)
|
||||||
|
}
|
46
frontend/src/components/Scaffold.css
Обычный файл
46
frontend/src/components/Scaffold.css
Обычный файл
@ -0,0 +1,46 @@
|
|||||||
|
.scaffold {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .top-bar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .content {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .bottom-bar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .bottom-bar > aside {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .bottom-bar > aside > * {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .bottom-bar > aside > * > * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaffold > .bottom-bar > aside > .floating-action-button {
|
||||||
|
text-align: right;
|
||||||
|
}
|
25
frontend/src/components/Scaffold.js
Обычный файл
25
frontend/src/components/Scaffold.js
Обычный файл
@ -0,0 +1,25 @@
|
|||||||
|
import './Scaffold.css'
|
||||||
|
|
||||||
|
export default function Scaffold({
|
||||||
|
topBar,
|
||||||
|
bottomBar,
|
||||||
|
snackbarHost,
|
||||||
|
floatingActionButton,
|
||||||
|
content,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="scaffold">
|
||||||
|
<div className="top-bar">{topBar}</div>
|
||||||
|
<div className="content">
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
<div className="bottom-bar">
|
||||||
|
<aside>
|
||||||
|
<div className="snackbar">{snackbarHost}</div>
|
||||||
|
<div className="floating-action-button">{floatingActionButton}</div>
|
||||||
|
</aside>
|
||||||
|
{bottomBar}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
0
frontend/src/components/Snackbar.css
Обычный файл
0
frontend/src/components/Snackbar.css
Обычный файл
0
frontend/src/components/Snackbar.js
Обычный файл
0
frontend/src/components/Snackbar.js
Обычный файл
20
frontend/src/components/TopAppBar.css
Обычный файл
20
frontend/src/components/TopAppBar.css
Обычный файл
@ -0,0 +1,20 @@
|
|||||||
|
.top-app-bar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: .5rem;
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-app-bar > * {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-app-bar > .title {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
22
frontend/src/components/TopAppBar.js
Обычный файл
22
frontend/src/components/TopAppBar.js
Обычный файл
@ -0,0 +1,22 @@
|
|||||||
|
import '@material/web/iconbutton/icon-button'
|
||||||
|
import '@material/web/icon/icon'
|
||||||
|
import '@material/web/button/filled-button'
|
||||||
|
|
||||||
|
import './TopAppBar.css'
|
||||||
|
|
||||||
|
export default function TopAppBar({
|
||||||
|
onDismissRequest,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="top-app-bar">
|
||||||
|
<md-icon-button onClick={() => onDismissRequest()}>
|
||||||
|
<md-icon>close</md-icon>
|
||||||
|
</md-icon-button>
|
||||||
|
<div className="title md-typescale-title-large">Изменить опрос</div>
|
||||||
|
<md-filled-button onClick={() => onDismissRequest()}>Сохранить</md-filled-button>
|
||||||
|
<md-icon-button>
|
||||||
|
<md-icon>more_vert</md-icon>
|
||||||
|
</md-icon-button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -6,3 +6,17 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import '@material/web/fab/fab'
|
||||||
|
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App'
|
import MainActivity from "./activities/MainActivity";
|
||||||
import BottomNavBar from "./BottomNavBar"
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'))
|
const root = ReactDOM.createRoot(document.getElementById('root'))
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<MainActivity />
|
||||||
<BottomNavBar />
|
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
)
|
)
|
||||||
|
0
frontend/src/screens/ChatsScreen.css
Обычный файл
0
frontend/src/screens/ChatsScreen.css
Обычный файл
0
frontend/src/screens/ChatsScreen.js
Обычный файл
0
frontend/src/screens/ChatsScreen.js
Обычный файл
0
frontend/src/screens/DashboardScreen.css
Обычный файл
0
frontend/src/screens/DashboardScreen.css
Обычный файл
0
frontend/src/screens/DashboardScreen.js
Обычный файл
0
frontend/src/screens/DashboardScreen.js
Обычный файл
0
frontend/src/screens/PollsScreen.css
Обычный файл
0
frontend/src/screens/PollsScreen.css
Обычный файл
138
frontend/src/screens/PollsScreen.js
Обычный файл
138
frontend/src/screens/PollsScreen.js
Обычный файл
@ -0,0 +1,138 @@
|
|||||||
|
import React, {useEffect, useState} from "react"
|
||||||
|
import '@material/web/textfield/outlined-text-field'
|
||||||
|
import '@material/web/fab/fab'
|
||||||
|
import '@material/web/icon/icon'
|
||||||
|
import '@material/web/select/outlined-select'
|
||||||
|
import '@material/web/select/select-option'
|
||||||
|
import '@material/web/list/list'
|
||||||
|
import '@material/web/list/list-item'
|
||||||
|
|
||||||
|
import FullScreenDialog from "../components/FullScreenDialog"
|
||||||
|
import PollListItem from "../components/PollListItem"
|
||||||
|
|
||||||
|
import './PollsScreen.css'
|
||||||
|
|
||||||
|
const PollContext = React.createContext({
|
||||||
|
polls: [],
|
||||||
|
fetchPolls: () => {},
|
||||||
|
})
|
||||||
|
|
||||||
|
const apiUrl = new URL(location)
|
||||||
|
apiUrl.pathname = '/api/polls'
|
||||||
|
|
||||||
|
export default function PollsScreen() {
|
||||||
|
const [polls, setPolls] = useState([])
|
||||||
|
const [editPoll, setEditPoll] = useState(false)
|
||||||
|
|
||||||
|
const fetchPolls = async () => {
|
||||||
|
const response = await fetch('/api/polls')
|
||||||
|
const polls = await response.json()
|
||||||
|
setPolls(polls)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePoll = async (poll) => {
|
||||||
|
await fetch(apiUrl, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(poll)
|
||||||
|
})
|
||||||
|
await fetchPolls()
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchPolls()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="polls-screen">
|
||||||
|
|
||||||
|
<md-list>
|
||||||
|
<PollContext.Provider value={{polls, fetchPolls}}>
|
||||||
|
{polls.map((poll) => (
|
||||||
|
PollListItem(poll, setEditPoll, updatePoll)
|
||||||
|
))}
|
||||||
|
</PollContext.Provider>
|
||||||
|
</md-list>
|
||||||
|
|
||||||
|
<FullScreenDialog
|
||||||
|
setEditPoll={setEditPoll}
|
||||||
|
classList={editPoll ? 'open' : 'close'}>
|
||||||
|
|
||||||
|
<md-outlined-text-field
|
||||||
|
label="Название"
|
||||||
|
value={editPoll ? editPoll.name : ''}
|
||||||
|
required="required">
|
||||||
|
<md-icon slot="leading-icon">title</md-icon>
|
||||||
|
</md-outlined-text-field>
|
||||||
|
|
||||||
|
<md-outlined-select label="Дни недели" required="required">
|
||||||
|
|
||||||
|
<md-icon slot="leading-icon">date_range</md-icon>
|
||||||
|
|
||||||
|
<md-select-option value="mon">
|
||||||
|
<div slot="headline">Понедельник</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="tue">
|
||||||
|
<div slot="headline">Вторник</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="wed">
|
||||||
|
<div slot="headline">Среда</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="thu">
|
||||||
|
<div slot="headline">Четверг</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="fri">
|
||||||
|
<div slot="headline">Пятница</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="sat">
|
||||||
|
<div slot="headline">Суббота</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
<md-select-option value="sun">
|
||||||
|
<div slot="headline">Воскресенье</div>
|
||||||
|
</md-select-option>
|
||||||
|
|
||||||
|
</md-outlined-select>
|
||||||
|
|
||||||
|
<section id="poll-messages">
|
||||||
|
<div className="md-typescale-title-medium">Сообщения</div>
|
||||||
|
<md-list>
|
||||||
|
<md-list-item>
|
||||||
|
Fruits
|
||||||
|
</md-list-item>
|
||||||
|
<md-divider></md-divider>
|
||||||
|
<md-list-item>
|
||||||
|
Apple
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
Banana
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<div slot="headline">Cucumber</div>
|
||||||
|
<div slot="supporting-text">Cucumbers are long green fruits that are just as long as this
|
||||||
|
multi-line description
|
||||||
|
</div>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item
|
||||||
|
type="link"
|
||||||
|
href="https://google.com/search?q=buy+kiwis&tbm=shop"
|
||||||
|
target="_blank">
|
||||||
|
<div slot="headline">Shop for Kiwis</div>
|
||||||
|
<div slot="supporting-text">This will link you out in a new tab</div>
|
||||||
|
<md-icon slot="end">open_in_new</md-icon>
|
||||||
|
</md-list-item>
|
||||||
|
</md-list>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</FullScreenDialog>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
0
frontend/src/screens/UsersScreen.css
Обычный файл
0
frontend/src/screens/UsersScreen.css
Обычный файл
0
frontend/src/screens/UsersScreen.js
Обычный файл
0
frontend/src/screens/UsersScreen.js
Обычный файл
Загрузка…
Ссылка в новой задаче
Block a user