mirror of
https://github.com/IT4Change/ohmyform-ui.git
synced 2025-12-13 09:45:50 +00:00
init
This commit is contained in:
commit
ac03ca3250
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# development environments
|
||||||
|
/.idea
|
||||||
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/zeit/next.js/) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||||
24
assets/global.scss
Normal file
24
assets/global.scss
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
@import "variables";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--backgroundColor: #{$background-color};
|
||||||
|
--primaryColor: #{$primary-color};
|
||||||
|
--textColorSecondary: #{$text-color-secondary};
|
||||||
|
|
||||||
|
--amplify-primary-color: #{$primary-color};
|
||||||
|
--amplify-primary-tint: #{lighten($primary-color, 0.1)};
|
||||||
|
--amplify-primary-shade: #{$primary-color};
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.3s;
|
||||||
|
color: #FFF;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/images/logo_white.png
Normal file
BIN
assets/images/logo_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
assets/images/logo_white_small.png
Normal file
BIN
assets/images/logo_white_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
3
assets/variables.scss
Normal file
3
assets/variables.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
$background-color: #f7f7f7;
|
||||||
|
$primary-color: #4182e4;
|
||||||
|
$text-color-secondary: rgba(0, 0, 0, 0.45);
|
||||||
20
components/date.time.tsx
Normal file
20
components/date.time.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import dayjs from 'dayjs'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
date: string
|
||||||
|
|
||||||
|
hideTime?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DateTime: React.FC<Props> = props => {
|
||||||
|
const format = props.hideTime ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
display: 'inline-block'
|
||||||
|
}}>
|
||||||
|
{dayjs(props.date).format(format)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
40
components/sidemenu.tsx
Normal file
40
components/sidemenu.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {HomeOutlined, MessageOutlined, TeamOutlined} from '@ant-design/icons'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export interface SideMenuElement {
|
||||||
|
items?: SideMenuElement[]
|
||||||
|
|
||||||
|
key: string
|
||||||
|
name: string
|
||||||
|
group?: boolean
|
||||||
|
href?: string
|
||||||
|
icon?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sideMenu: SideMenuElement[] = [
|
||||||
|
{
|
||||||
|
key: 'home',
|
||||||
|
name: 'Home',
|
||||||
|
href: '/',
|
||||||
|
icon: <HomeOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'communication',
|
||||||
|
name: 'Communication',
|
||||||
|
group: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
key: 'users',
|
||||||
|
name: 'Users',
|
||||||
|
href: '/users',
|
||||||
|
icon: <TeamOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'chats',
|
||||||
|
name: 'Chats',
|
||||||
|
href: '/chats',
|
||||||
|
icon: <MessageOutlined />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
270
components/structure.tsx
Normal file
270
components/structure.tsx
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
import {CaretDownOutlined, UserOutlined} from '@ant-design/icons'
|
||||||
|
import {MenuFoldOutlined, MenuUnfoldOutlined} from '@ant-design/icons/lib'
|
||||||
|
import {Dropdown, Layout, Menu, PageHeader, Spin, Tag} from 'antd'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useRouter} from 'next/router'
|
||||||
|
import React, {FunctionComponent} from 'react'
|
||||||
|
import {sideMenu, SideMenuElement} from './sidemenu'
|
||||||
|
import {useWindowSize} from './use.window.size'
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig()
|
||||||
|
|
||||||
|
const { SubMenu, ItemGroup } = Menu
|
||||||
|
const { Header, Content, Sider } = Layout
|
||||||
|
|
||||||
|
interface BreadcrumbEntry {
|
||||||
|
name: string
|
||||||
|
href?: string
|
||||||
|
as?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
loading?: boolean
|
||||||
|
padded?: boolean
|
||||||
|
style?: any
|
||||||
|
|
||||||
|
selected?: string
|
||||||
|
|
||||||
|
|
||||||
|
breadcrumbs?: BreadcrumbEntry[]
|
||||||
|
title?: string
|
||||||
|
subTitle?: string
|
||||||
|
extra?: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const Structure: FunctionComponent<Props> = (props) => {
|
||||||
|
const size = useWindowSize()
|
||||||
|
const [userMenu, setUserMenu] = React.useState(false)
|
||||||
|
const [open, setOpen] = React.useState<string[]>()
|
||||||
|
const [selected, setSelected] = React.useState<string[]>()
|
||||||
|
const [sidebar, setSidebar] = React.useState(size.width < 700)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (sidebar !== size.width < 700) {
|
||||||
|
setSidebar(size.width < 700)
|
||||||
|
}
|
||||||
|
}, [size.width])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (props.selected) {
|
||||||
|
const parts = props.selected.split('.')
|
||||||
|
|
||||||
|
const last = parts.pop()
|
||||||
|
|
||||||
|
if (parts.length > 0) {
|
||||||
|
setOpen(parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected([last])
|
||||||
|
}
|
||||||
|
}, [props.selected])
|
||||||
|
|
||||||
|
const buildMenu = (data: SideMenuElement[]): JSX.Element[] => {
|
||||||
|
return data.map((element): JSX.Element => {
|
||||||
|
if (element.items && element.items.length > 0) {
|
||||||
|
if (element.group) {
|
||||||
|
return (
|
||||||
|
<ItemGroup
|
||||||
|
key={element.key}
|
||||||
|
title={(
|
||||||
|
<div style={{
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
paddingTop: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#444'
|
||||||
|
}}>
|
||||||
|
{element.icon}
|
||||||
|
{element.name}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{buildMenu(element.items)}
|
||||||
|
</ItemGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SubMenu
|
||||||
|
key={element.key}
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
{element.icon}
|
||||||
|
{element.name}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{buildMenu(element.items)}
|
||||||
|
</SubMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu.Item
|
||||||
|
onClick={(): void => {
|
||||||
|
if (element.href) {
|
||||||
|
router.push(element.href)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
key={element.key}
|
||||||
|
>
|
||||||
|
{element.icon}
|
||||||
|
{element.name}
|
||||||
|
</Menu.Item>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const signOut = async (): Promise<void> => {
|
||||||
|
// TODO sign out
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout style={{ height: '100vh' }}>
|
||||||
|
<Header
|
||||||
|
style={{
|
||||||
|
paddingLeft: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{
|
||||||
|
float: 'left',
|
||||||
|
color: '#FFF',
|
||||||
|
fontSize: 14,
|
||||||
|
marginRight: 26,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}>
|
||||||
|
{React.createElement(sidebar ? MenuUnfoldOutlined : MenuFoldOutlined, {
|
||||||
|
className: 'sidebar-toggle',
|
||||||
|
onClick: () => setSidebar(!sidebar),
|
||||||
|
})}
|
||||||
|
|
||||||
|
<img src={require('assets/images/logo_white_small.png')} height={30} style={{marginRight: 16}} alt={'RecTag'} />
|
||||||
|
|
||||||
|
{publicRuntimeConfig.area.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
<div style={{float: 'right', display: 'flex', height: '100%'}}>
|
||||||
|
<Dropdown
|
||||||
|
overlay={(
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item onClick={(): void => console.log('profile??')}>Profile</Menu.Item>
|
||||||
|
<Menu.Divider/>
|
||||||
|
<Menu.Item onClick={signOut}>Logout</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
)}
|
||||||
|
onVisibleChange={setUserMenu}
|
||||||
|
visible={userMenu}
|
||||||
|
>
|
||||||
|
<a style={{
|
||||||
|
color: '#FFF',
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'inline-flex',
|
||||||
|
}}>
|
||||||
|
<UserOutlined style={{fontSize: 24}} />
|
||||||
|
<CaretDownOutlined />
|
||||||
|
</a>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</Header>
|
||||||
|
<Layout style={{
|
||||||
|
height: '100%',
|
||||||
|
}}>
|
||||||
|
<Sider
|
||||||
|
collapsed={sidebar}
|
||||||
|
trigger={null}
|
||||||
|
collapsedWidth={0}
|
||||||
|
breakpoint={'xs'}
|
||||||
|
width={200}
|
||||||
|
style={{
|
||||||
|
background: '#fff',
|
||||||
|
maxHeight: '100%',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
mode="inline"
|
||||||
|
defaultSelectedKeys={['1']}
|
||||||
|
selectedKeys={selected}
|
||||||
|
onSelect={(s): void => setSelected(s.keyPath)}
|
||||||
|
openKeys={open}
|
||||||
|
onOpenChange={(open): void => setOpen(open)}
|
||||||
|
>
|
||||||
|
{buildMenu(sideMenu)}
|
||||||
|
</Menu>
|
||||||
|
<Menu
|
||||||
|
mode="inline"
|
||||||
|
selectable={false}
|
||||||
|
>
|
||||||
|
<Menu.Item
|
||||||
|
style={{
|
||||||
|
marginTop: 40,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Version: <Tag color="gold">{publicRuntimeConfig.version}</Tag>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
</Sider>
|
||||||
|
<Layout style={{ padding: '0 24px 24px' }}>
|
||||||
|
{props.title && (
|
||||||
|
<PageHeader
|
||||||
|
title={props.title}
|
||||||
|
subTitle={props.subTitle}
|
||||||
|
extra={props.extra}
|
||||||
|
breadcrumb={{
|
||||||
|
routes: [
|
||||||
|
...(props.breadcrumbs || []).map(b => ({
|
||||||
|
breadcrumbName: b.name,
|
||||||
|
path: ''
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
breadcrumbName: props.title,
|
||||||
|
path: ''
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: props.breadcrumbs,
|
||||||
|
itemRender: (route, params: BreadcrumbEntry[], routes, paths) => {
|
||||||
|
if (routes.indexOf(route) === routes.length - 1) {
|
||||||
|
return <span>{route.breadcrumbName}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = params[routes.indexOf(route)]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={entry.href}
|
||||||
|
as={entry.as || entry.href}
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
{entry.name}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Spin
|
||||||
|
spinning={!!props.loading}
|
||||||
|
>
|
||||||
|
<Content
|
||||||
|
style={{
|
||||||
|
background: props.padded ? '#fff' : null,
|
||||||
|
padding: props.padded ? 24 : 0,
|
||||||
|
...props.style
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Content>
|
||||||
|
</Spin>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Structure.defaultProps = {
|
||||||
|
padded: true,
|
||||||
|
style: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Structure
|
||||||
23
components/time.ago.tsx
Normal file
23
components/time.ago.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {Tooltip} from 'antd'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TimeAgo: React.FC<Props> = props => {
|
||||||
|
const date = dayjs(props.date)
|
||||||
|
return (
|
||||||
|
<Tooltip title={date.format('YYYY-MM-DD HH:mm:ss')}>
|
||||||
|
<div style={{
|
||||||
|
display: 'inline-block'
|
||||||
|
}}>
|
||||||
|
{date.fromNow()}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
29
components/use.window.size.ts
Normal file
29
components/use.window.size.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {useEffect, useState} from 'react'
|
||||||
|
|
||||||
|
export const useWindowSize = () => {
|
||||||
|
const isClient = typeof window === 'object';
|
||||||
|
|
||||||
|
function getSize() {
|
||||||
|
return {
|
||||||
|
width: isClient ? window.innerWidth : undefined,
|
||||||
|
height: isClient ? window.innerHeight : undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [windowSize, setWindowSize] = useState(getSize);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isClient) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResize() {
|
||||||
|
setWindowSize(getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, []); // Empty array ensures that effect is only run on mount and unmount
|
||||||
|
|
||||||
|
return windowSize;
|
||||||
|
}
|
||||||
59
components/with.auth.tsx
Normal file
59
components/with.auth.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import {Spin} from 'antd'
|
||||||
|
import {AxiosRequestConfig} from 'axios'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig()
|
||||||
|
|
||||||
|
export const authConfig = async (config: AxiosRequestConfig = {}): Promise<AxiosRequestConfig> => {
|
||||||
|
if (!config.headers) {
|
||||||
|
config.headers = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO config.headers.Authorization = `Bearer ${session.getAccessToken().getJwtToken()}`
|
||||||
|
} catch (e) {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
export const withAuth = (Component): React.FC => {
|
||||||
|
return props => {
|
||||||
|
const [signedIn, setSignedIn] = React.useState(false);
|
||||||
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
height: '100vh',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<Spin size="large"/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signedIn) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Component {...props} />
|
||||||
|
};
|
||||||
|
}
|
||||||
2
next-env.d.ts
vendored
Normal file
2
next-env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/types/global" />
|
||||||
11
next.config.js
Normal file
11
next.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const withImages = require('next-images')
|
||||||
|
const module = require('./package.json')
|
||||||
|
|
||||||
|
const version = module.version;
|
||||||
|
|
||||||
|
module.exports = withImages({
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
endpoint: process.env.API_HOST || '/graphql',
|
||||||
|
version,
|
||||||
|
}
|
||||||
|
})
|
||||||
33
package.json
Normal file
33
package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "ohmyform-react",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"export": "next build && next export",
|
||||||
|
"start": "next start"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^4.1.0",
|
||||||
|
"antd": "^4.2.2",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"dayjs": "^1.8.27",
|
||||||
|
"next": "9.4.0",
|
||||||
|
"next-images": "^1.4.0",
|
||||||
|
"next-redux-wrapper": "^6.0.0",
|
||||||
|
"react": "16.13.1",
|
||||||
|
"react-dom": "16.13.1",
|
||||||
|
"react-icons": "^3.10.0",
|
||||||
|
"react-redux": "^7.2.0",
|
||||||
|
"redux": "^4.0.5",
|
||||||
|
"redux-devtools-extension": "^2.13.8",
|
||||||
|
"redux-thunk": "^2.3.0",
|
||||||
|
"sass": "^1.26.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^14.0.1",
|
||||||
|
"@types/react": "^16.9.35",
|
||||||
|
"typescript": "^3.9.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
25
pages/_app.tsx
Normal file
25
pages/_app.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'antd/dist/antd.css'
|
||||||
|
import 'assets/global.scss'
|
||||||
|
import 'assets/variables.scss'
|
||||||
|
import {AppProps} from 'next/app'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
import Head from 'next/head'
|
||||||
|
import React from 'react'
|
||||||
|
import {wrapper} from 'store'
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig()
|
||||||
|
|
||||||
|
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>OhMyForm</title>
|
||||||
|
<meta name="theme-color" content={'#4182e4'} />
|
||||||
|
</Head>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default wrapper.withRedux(App)
|
||||||
|
// export default App
|
||||||
0
pages/admin/index.tsx
Normal file
0
pages/admin/index.tsx
Normal file
18
pages/index.tsx
Normal file
18
pages/index.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Alert} from 'antd'
|
||||||
|
import {withAuth} from 'components/with.auth'
|
||||||
|
import {NextPage} from 'next'
|
||||||
|
import React from 'react'
|
||||||
|
import Structure from '../components/structure'
|
||||||
|
|
||||||
|
const Index: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<Structure
|
||||||
|
selected={'home'}
|
||||||
|
title={'Home'}
|
||||||
|
>
|
||||||
|
<Alert message={"Hi"}/>
|
||||||
|
</Structure>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withAuth(Index)
|
||||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
37
store/index.ts
Normal file
37
store/index.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {createWrapper, HYDRATE, MakeStore} from 'next-redux-wrapper'
|
||||||
|
import {AnyAction, applyMiddleware, combineReducers, createStore} from 'redux'
|
||||||
|
import {composeWithDevTools} from 'redux-devtools-extension'
|
||||||
|
import thunkMiddleware from 'redux-thunk'
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = {}
|
||||||
|
|
||||||
|
const root = (state: State, action: AnyAction) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case HYDRATE:
|
||||||
|
return {...state, ...action.payload};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeStore: MakeStore<State> = (context) => {
|
||||||
|
return createStore(
|
||||||
|
(state, action): State => {
|
||||||
|
const simple = combineReducers({
|
||||||
|
// TODO add child reducers
|
||||||
|
})
|
||||||
|
|
||||||
|
return root(simple, action)
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
composeWithDevTools(applyMiddleware(
|
||||||
|
thunkMiddleware,
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const wrapper = createWrapper<State>(makeStore, {debug: true});
|
||||||
|
|
||||||
30
tsconfig.json
Normal file
30
tsconfig.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve"
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx"
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user