25/3/2021
This commit is contained in:
parent
74b4a383b4
commit
40fb126d37
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["next/babel"],
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-decorators",
|
|
||||||
{
|
|
||||||
"legacy": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-class-properties",
|
|
||||||
{
|
|
||||||
"loose": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
@ -12,6 +12,8 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"bootstrap": "^5.0.0-beta3",
|
||||||
"mobx": "^6.1.8",
|
"mobx": "^6.1.8",
|
||||||
"mobx-react": "^7.1.0",
|
"mobx-react": "^7.1.0",
|
||||||
"next": "^10.0.9",
|
"next": "^10.0.9",
|
||||||
@ -24,6 +26,7 @@
|
|||||||
"@babel/plugin-proposal-decorators": "^7.13.5",
|
"@babel/plugin-proposal-decorators": "^7.13.5",
|
||||||
"@types/node": "^14.14.35",
|
"@types/node": "^14.14.35",
|
||||||
"@types/react": "^17.0.3",
|
"@types/react": "^17.0.3",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
Next/pages/customer.tsx
Normal file
65
Next/pages/customer.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { Layout } from './shared/Layout';
|
||||||
|
|
||||||
|
interface CustomerListItem {
|
||||||
|
customerID: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
function RenderCustomerListItemRows(customers: CustomerListItem[]) {
|
||||||
|
let rows = customers.map(x => {
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{x.name}</td>
|
||||||
|
<td>{x.email}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<tbody>
|
||||||
|
{rows}
|
||||||
|
</tbody>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
class Customer extends React.Component<{}, {customer: CustomerListItem[] }> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
customer: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async componentDidMount() {
|
||||||
|
try {
|
||||||
|
let data = await axios.get<CustomerListItem[]>("http://localhost:5000/api/customer");0
|
||||||
|
console.log(data.data);
|
||||||
|
this.setState({
|
||||||
|
customer: data.data
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.setState({
|
||||||
|
customer: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<table className="table table-hover table-striped table-sm">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
</tr>
|
||||||
|
{RenderCustomerListItemRows(this.state.customer)}
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CustomerPage() {
|
||||||
|
return (
|
||||||
|
<Layout title="Customers">
|
||||||
|
<Customer></Customer>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
@ -1,24 +1,37 @@
|
|||||||
import { makeObservable, observable, action } from 'mobx';
|
import { makeObservable, observable, action } from 'mobx';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Layout } from './shared/Layout';
|
||||||
|
|
||||||
@observer class Index extends React.Component {
|
class Index extends React.Component {
|
||||||
@observable x: number = 0;
|
x: number = 0;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
makeObservable(this, {
|
||||||
|
x: observable,
|
||||||
|
clickMe: action,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
clickMe() {
|
clickMe() {
|
||||||
this.x += 1;
|
this.x += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
<button onClick={this.clickMe.bind(this)}>{this.x}</button>
|
<button onClick={this.clickMe.bind(this)}>{this.x}</button>
|
||||||
|
<Link href="/todo">Go to Todo</Link>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Index;
|
|
||||||
|
export default function IndexPage() {
|
||||||
|
return (<Layout title="Home">
|
||||||
|
<Index></Index>
|
||||||
|
</Layout>);
|
||||||
|
}
|
79
Next/pages/shared/Layout.tsx
Normal file
79
Next/pages/shared/Layout.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Head from 'next/head'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||||
|
|
||||||
|
const NavLink: React.FunctionComponent<{href: string}> = ({href, children}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const NavLinkClasses = (active) => {
|
||||||
|
if(active) {
|
||||||
|
return "nav-link active";
|
||||||
|
} else {
|
||||||
|
return "nav-link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const NavLinkCurrent = (active) => {
|
||||||
|
if(active) {
|
||||||
|
return "page";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const active = router.pathname == href;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className='nav-item active'>
|
||||||
|
<Link href={href}>
|
||||||
|
<a className={NavLinkClasses(active)} aria-current={NavLinkCurrent}>{children}</a>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NavBar: React.FunctionComponent<{}> = () => {
|
||||||
|
return (
|
||||||
|
<nav className='navbar navbar-expand-lg navbar-light bg-light'>
|
||||||
|
<a className='navbar-brand' href='#'>
|
||||||
|
Navbar
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
className='navbar-toggler'
|
||||||
|
type='button'
|
||||||
|
data-toggle='collapse'
|
||||||
|
data-target='#navbarSupportedContent'
|
||||||
|
aria-controls='navbarSupportedContent'
|
||||||
|
aria-expanded='false'
|
||||||
|
aria-label='Toggle navigation'
|
||||||
|
>
|
||||||
|
<span className='navbar-toggler-icon' />
|
||||||
|
</button>
|
||||||
|
<div className='collapse navbar-collapse' id='navbarSupportedContent'>
|
||||||
|
<ul className='navbar-nav mr-auto'>
|
||||||
|
<NavLink href="/">Home</NavLink>
|
||||||
|
<NavLink href="/todo">Todo</NavLink>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export class Layout extends React.Component<{
|
||||||
|
title: string
|
||||||
|
}> {
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Head>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||||
|
<title>{this.props.title} - TestAppRuna</title>
|
||||||
|
</Head>
|
||||||
|
<header>
|
||||||
|
<NavBar />
|
||||||
|
</header>
|
||||||
|
<main>{this.props.children}</main>
|
||||||
|
<footer></footer>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
90
Next/pages/todo.tsx
Normal file
90
Next/pages/todo.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { observable, action, makeObservable } from 'mobx';
|
||||||
|
import { PropTypes } from 'mobx-react';
|
||||||
|
import { Layout } from './shared/Layout';
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
|
||||||
|
interface ToDoListItem {
|
||||||
|
todo: string,
|
||||||
|
checked: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToDoState {
|
||||||
|
inputText: string,
|
||||||
|
toDoList: ToDoListItem[],
|
||||||
|
}
|
||||||
|
|
||||||
|
const TodoItem: React.FunctionComponent<{
|
||||||
|
item: ToDoListItem,
|
||||||
|
onRemoveButtonClick: (id) => void
|
||||||
|
}> = ({ item, onRemoveButtonClick }) => {
|
||||||
|
let onClick = () => {
|
||||||
|
onRemoveButtonClick(item);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button onClick={onClick}>Remove</button>
|
||||||
|
{item.todo}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const TodoList: React.FunctionComponent<{
|
||||||
|
items: ToDoListItem[],
|
||||||
|
onChange?: (item) => void
|
||||||
|
}> = ({ items, onChange }) => {
|
||||||
|
const onRemoveButtonClick = (item) => {
|
||||||
|
if(onChange) {
|
||||||
|
onChange(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const listItems = items.map(Q => <TodoItem onRemoveButtonClick={onRemoveButtonClick} item={Q}></TodoItem>)
|
||||||
|
return <div>{listItems}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Todo extends React.Component<{},ToDoState> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
inputText: "",
|
||||||
|
toDoList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
onTextInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
this.setState({
|
||||||
|
inputText: e.target.value,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
onChange = (item) => {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
toDoList: this.state.toDoList.filter(x => item.todo != x.todo)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
addList = () => {
|
||||||
|
this.setState({
|
||||||
|
inputText: "",
|
||||||
|
toDoList: [...this.state.toDoList, {
|
||||||
|
todo: this.state.inputText, checked: false
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input value={this.state.inputText} onChange={this.onTextInput}></input>
|
||||||
|
{this.state.inputText}
|
||||||
|
</div>
|
||||||
|
<button onClick={this.addList}>Add</button>
|
||||||
|
<TodoList onChange={this.onChange} items={this.state.toDoList}></TodoList>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return <Layout title="Todo"><Todo></Todo></Layout>
|
||||||
|
}
|
@ -23,8 +23,7 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true
|
||||||
"experimentalDecorators": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
1895
Next/yarn.lock
Normal file
1895
Next/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
25
TestAppRuna/.vscode/launch.json
vendored
Normal file
25
TestAppRuna/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/net5.0/TestAppRuna.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach",
|
||||||
|
"processId": "${command:pickProcess}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
24
TestAppRuna/.vscode/tasks.json
vendored
Normal file
24
TestAppRuna/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "shell",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
// Ask dotnet build to generate full paths for file names.
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "silent"
|
||||||
|
},
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -14,7 +14,6 @@ namespace TestAppRuna.API
|
|||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize(AuthenticationSchemes = "nanaoaccounts")]
|
|
||||||
public class CustomerController : ControllerBase
|
public class CustomerController : ControllerBase
|
||||||
{
|
{
|
||||||
public CustomerController(ShopDbContext shopDbContext)
|
public CustomerController(ShopDbContext shopDbContext)
|
||||||
|
@ -51,6 +51,11 @@ namespace TestAppRuna
|
|||||||
options.Audience = "testappruna";
|
options.Audience = "testappruna";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
services.AddCors(options => {
|
||||||
|
options.AddPolicy("BelajarNextJS", policy => {
|
||||||
|
policy.WithOrigins("http://localhost:3000");
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
@ -85,6 +90,8 @@ namespace TestAppRuna
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseCors("BelajarNextJS");
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapDefaultControllerRoute();
|
endpoints.MapDefaultControllerRoute();
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
|
||||||
<PackageReference Include="NSwag.AspNetCore" Version="13.10.8" />
|
<PackageReference Include="NSwag.AspNetCore" Version="13.10.8" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="4.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
|
<PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"tslib": "^2.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
devDependencies:
|
|
||||||
tslib: 2.1.0
|
|
||||||
lockfileVersion: 5.2
|
|
||||||
packages:
|
|
||||||
/tslib/2.1.0:
|
|
||||||
dev: true
|
|
||||||
resolution:
|
|
||||||
integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
|
||||||
specifiers:
|
|
||||||
tslib: ^2.1.0
|
|
Loading…
Reference in New Issue
Block a user