Skip to content
This repository has been archived by the owner on Jan 3, 2025. It is now read-only.

Commit

Permalink
UI group management
Browse files Browse the repository at this point in the history
  • Loading branch information
Huy Le Tien committed Apr 13, 2022
1 parent 44348b5 commit cd47a1f
Show file tree
Hide file tree
Showing 16 changed files with 314 additions and 32 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@craco/craco": "^6.4.3",
"@reduxjs/toolkit": "^1.8.1",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"antd": "^4.19.5",
"antd": "^4.19.2",
"aws-amplify": "^4.3.19",
"axios": "^0.26.1",
"craco-less": "^2.0.0",
Expand All @@ -20,6 +21,7 @@
"react-scripts": "5.0.0",
"redux-saga": "^1.1.3",
"styled-components": "^5.3.5",
"tailwindcss": "^3.0.24",
"typescript": "^4.1.6"
},
"scripts": {
Expand Down
10 changes: 5 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Card } from "antd";
import Layout from "components/Layout";
import { logout, selectUserSelector } from "containers/Auth/authSlice";
import withAuth from "helpers/withAuth";
import React, { useEffect } from "react";
Expand All @@ -15,12 +17,10 @@ function App() {
}, []);

return (
<div className="App">
Hello World, {user?.username},
<button onClick={() => dispatch(logout())}>Logout</button>
</div>
<Layout>
<Card>Hello World</Card>
</Layout>
);
}

export default withAuth(App);

16 changes: 11 additions & 5 deletions src/components/Auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import React from "react";
import styled from "styled-components";

interface IProps {
loading?: boolean;
onFinish: any;
}

export default function LoginForm({ onFinish }: IProps) {
export default function LoginForm({ onFinish, loading }: IProps) {
return (
<FormContainer>
<h1>B2B Admin Portal</h1>
Expand All @@ -24,7 +25,7 @@ export default function LoginForm({ onFinish }: IProps) {
rules={[
{
required: true,
message: "Required field",
message: "Please input required field",
},
]}
>
Expand All @@ -35,13 +36,13 @@ export default function LoginForm({ onFinish }: IProps) {
rules={[
{
required: true,
message: "Required field",
message: "Please input required field",
},
]}
>
<Input.Password placeholder="Password" />
</Form.Item>
<Button htmlType="submit" type="primary" block>
<Button loading={loading} htmlType="submit" type="primary" block>
Sign in
</Button>
</Form>
Expand All @@ -60,9 +61,14 @@ const FormContainer = styled.div`
justify-content: center;
align-items: center;
flex-direction: column;
h1 {
font-weight: bold;
}
`;

const FormContent = styled(Card)`
border: 0;
max-width: 90%;
width: 350px;
width: 400px;
`;
100 changes: 100 additions & 0 deletions src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Button, Menu } from "antd";
import { logout, selectUserSelector } from "containers/Auth/authSlice";
import { useMemo, useState } from "react";
import {
RiGroupLine,
RiHome3Line,
RiMenuFoldLine,
RiMenuUnfoldLine,
RiUserLine,
} from "react-icons/ri";
import { useDispatch, useSelector } from "react-redux";
import { Link, useLocation } from "react-router-dom";

import {
StyledContent,
StyledHeader,
StyledLayout,
StyledSider,
} from "./style";

interface IProps {
children?: any;
}

const Layout = (props: IProps) => {
const [collapsed, setCollapsed] = useState(false);
const user = useSelector(selectUserSelector);
const dispatch = useDispatch();
const location = useLocation();

const toggle = () => {
setCollapsed(!collapsed);
};

const openKeys = useMemo(() => {
const list = location.pathname.split("/").filter(Boolean);

return list.map((item, index) => `${item}-submenu`);
}, [location.pathname]);

return (
<StyledLayout>
<StyledSider
theme="light"
trigger={null}
collapsible
collapsed={collapsed}
>
<div className="logo" />
<Menu
mode="inline"
selectedKeys={[location.pathname]}
defaultOpenKeys={openKeys}
>
<Menu.Item key="/" icon={<RiHome3Line size={18} />}>
<Link to="/">Home</Link>
</Menu.Item>
<Menu.SubMenu
key="users-submenu"
icon={<RiUserLine size={18} />}
title="Users"
>
<Menu.Item key="/users" icon={<RiUserLine size={18} />}>
<Link to="/users">Users</Link>
</Menu.Item>
<Menu.Item key="/users/groups" icon={<RiGroupLine size={18} />}>
<Link to="/users/groups">Groups</Link>
</Menu.Item>
</Menu.SubMenu>
</Menu>
</StyledSider>
<StyledLayout>
<StyledHeader style={{ padding: 0 }}>
<Button
type="link"
onClick={toggle}
icon={
collapsed ? (
<RiMenuUnfoldLine size={24} />
) : (
<RiMenuFoldLine size={24} />
)
}
/>
<div className="flex flex-1 justify-end px-5">
<span>
Hi, <b>{user?.username}</b> -{" "}
<a href="#" onClick={() => dispatch(logout())}>
Logout
</a>
</span>
</div>
</StyledHeader>
<StyledContent>{props.children}</StyledContent>
</StyledLayout>
</StyledLayout>
);
};

export default Layout;
24 changes: 24 additions & 0 deletions src/components/Layout/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styled from "styled-components";
import { Layout } from "antd";

export const StyledLayout = styled(Layout)`
height: 100%;
`;

export const StyledContent = styled(Layout.Content)`
padding: 20px;
`;

export const StyledHeader = styled(Layout.Header)`
display: flex;
background-color: #fff;
align-items: center;
`;

export const StyledSider = styled(Layout.Sider)`
.logo {
height: 54px;
margin: 10px;
background-color: #ccc;
}
`;
16 changes: 13 additions & 3 deletions src/containers/Auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { notification } from "antd";
import { Auth } from "aws-amplify";
import LoginForm from "components/Auth/LoginForm";
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { setUserInfo } from "./authSlice";

function Login() {
const [loading, setLoading] = useState(false);
const dispatch = useDispatch();
const navigate = useNavigate();

const handleLogin = async ({ username, password }: any) => {
try {
setLoading(true);
const result = await Auth.signIn(username, password);

dispatch(
Expand All @@ -25,10 +28,17 @@ function Login() {
);

navigate("/");
} catch (error) {}
} catch (error: any) {
notification.error({
message: "Error!",
description: error?.message,
});
} finally {
setLoading(false);
}
};

return <LoginForm onFinish={handleLogin} />;
return <LoginForm loading={loading} onFinish={handleLogin} />;
}

export default Login;
1 change: 0 additions & 1 deletion src/containers/Auth/index.tsx

This file was deleted.

54 changes: 54 additions & 0 deletions src/containers/User/Group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Breadcrumb, Button, Card, Form, Input, Modal, Table } from "antd";
import Layout from "components/Layout";
import withAuth from "helpers/withAuth";
import React from "react";

const columns = [
{
title: "Permission",
},
{
title: "Read",
},
{
title: "Write",
},
];

function Group() {
const [visible, setVisible] = React.useState(false);
return (
<Layout>
<Breadcrumb style={{ marginBottom: 10 }} separator=">">
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item href="/users">Users</Breadcrumb.Item>
<Breadcrumb.Item>Groups</Breadcrumb.Item>
</Breadcrumb>
<Card
extra={
<Button type="primary" onClick={() => setVisible(true)}>
Add Group
</Button>
}
></Card>
<Modal
visible={visible}
title="Add Group"
okText="Save"
onCancel={() => setVisible(false)}
>
<Form layout="vertical">
<Form.Item label="Group Name">
<Input />
</Form.Item>
<Form.Item label="Group Description">
<Input />
</Form.Item>
<Table columns={columns} />
</Form>
</Modal>
</Layout>
);
}

export default withAuth(Group);
9 changes: 9 additions & 0 deletions src/containers/User/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Layout from "components/Layout";
import withAuth from "helpers/withAuth";
import React from "react";

function User() {
return <Layout>User</Layout>;
}

export default withAuth(User);
22 changes: 20 additions & 2 deletions src/index.less
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "~antd/dist/antd.less";

@font-family: "Roboto", sans-serif;
@padding-lg: 30px;
@padding-md: 24px;
// vertical paddings
@padding-lg: 30px; // containers
@padding-md: 24px; // small containers and buttons
@padding-sm: 18px; // Form controls and items
@padding-xs: 12px; // small items
@padding-xss: 8px; // more small

// vertical margins
@margin-lg: 30px; // containers
@margin-md: 24px; // small containers and buttons
@margin-sm: 18px; // Form controls and items
@margin-xs: 12px; // small items
@margin-xss: 8px; // more small

@border-radius-base: 5px;
@primary-color: #1f6dff;
@info-color: #20063b;
@success-color: #4ebc5e;
@warning-color: #ffb427;
@error-color: #ff3341;
@height-base: 40px;
@height-lg: 42px;
@height-sm: 32px;
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Auth } from "aws-amplify";
import config from "aws-exports";
import React from "react";
import ReactDOM from "react-dom";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import AppRouter from "routes";
import { store } from "store";
Expand Down
5 changes: 5 additions & 0 deletions src/react-app-env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
/// <reference types="react-scripts" />
declare module "react-dom/client" {
// typing module default export as `any` will allow you to access its members without compiler warning
var createRoot: any;
export { createRoot };
}
Loading

0 comments on commit cd47a1f

Please sign in to comment.