PR-610983: Creating the example project of a List Task App.

This commit is contained in:
2023-10-12 06:30:16 +00:00
parent f76a89eacb
commit dd3e108bca
20 changed files with 353 additions and 203 deletions

View File

@ -0,0 +1,65 @@
/* List */
export type TList = {
list: TItem[]
}
export interface IListPayload {
index?: number
item?: TItem
}
export type TItem = {
name: string,
status: Status
}
export enum Status {
TODO = 'TODO',
DONE = 'DONE'
}
export interface IAddItemToList {
type: ActionTypesList.AddItem
payload: IListPayload
}
export interface IChangeStatus {
type: ActionTypesList.ChangeStatus
payload: IListPayload
}
export interface IDeleteItemToList {
type: ActionTypesList.DeleteItem
payload: IListPayload
}
export enum ActionTypesList {
AddItem = 'ADD_ITEM',
ChangeStatus = 'CHANGE_STATUS',
DeleteItem = 'DELETE_ITEM'
}
export type TListAction = {
type: ActionTypesList
payload: IListPayload
}
const addItem = (payload: IAddItemToList) => ({
type: ActionTypesList.AddItem,
payload
});
const changeStatus = (payload: IChangeStatus) => ({
type: ActionTypesList.ChangeStatus,
payload
});
const listActions = {
addItem,
changeStatus
};
/* List */
export default listActions;

View File

@ -1,9 +0,0 @@
import test, { TTest } from './testAction';
export type TAction = TTest
const actions = {
test
}
export default actions

View File

@ -1,25 +0,0 @@
export enum ActionTypesTest {
ChangeHello = 'CHANGE_HELLO'
}
export interface IChangeHello {
type: ActionTypesTest.ChangeHello
payload: IChangeHelloPayload
}
export interface IChangeHelloPayload {
hello: any | undefined
}
export type TTest = IChangeHello
const changeHello = (payload: string) => ({
type: ActionTypesTest.ChangeHello,
payload
})
const actions = {
changeHello
}
export default actions

View File

@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,36 +0,0 @@
import React from 'react';
import './InitialComponent.scss';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
const InitialComponent = ({ hello }: { hello: string }) => {
return(
<div className="App">
<header className="App-header">
<img src="assets/img/logo.svg" className="App-logo" alt="logo" />
<p>This is the text from the store of redux: <strong>{hello}</strong></p>
<p>
Edit <code>src/frontend/InitialComponent.jsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<Link className="App-link" to="/other-component">Other Component</Link>
</header>
</div>
);
};
const mapStateToProps = (state) => {
return {
hello: state.testReducer.hello
};
};
export default connect(mapStateToProps)(InitialComponent);

View File

@ -0,0 +1,69 @@
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { TItem, ActionTypesList, Status } from '../actions/ListAction';
import 'react-list-ui-library/dist/index.css';
import { ContainerList, List } from 'react-list-ui-library';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ListComponent = ({ list, addItem, changeStatus, deleteItem }: {list: TItem[], addItem: (item: TItem) => any, changeStatus: (index: number) => any, deleteItem: (index: number) => any }) => {
const [itemName, setItemName] = useState<string>('');
const onClickAddItem = () => {
const item: TItem = {
name: itemName,
status: Status.TODO
};
if(itemName !== ''){
addItem(item);
setItemName('');
}else{
alert('Please, insert a name');
}
};
const onChangeInput = (e) => {
setItemName(e.target.value);
};
const handleChangeState = (index) => {
changeStatus(index);
};
const onClickRemoveItem = (index) => {
deleteItem(index);
};
return(
<div className="App">
<ContainerList title='List App'>
<List
list={list}
valueInput={itemName}
placeholderInput='Insert a name of a new item'
onChangeInput={onChangeInput}
onClickAddItem={onClickAddItem}
onClickRemoveItem={onClickRemoveItem}
handleChangeState={handleChangeState}
/>
</ContainerList>
</div>
);
};
const mapStateToProps = (state) => {
return {
list: state.listReducer.list
};
};
const mapDispatchToProps = (dispatch) => {
return {
addItem: (item: TItem) => dispatch({ type: ActionTypesList.AddItem, payload: { item: item } }),
changeStatus: (index: number) => dispatch({ type: ActionTypesList.ChangeStatus, payload: { index: index } }),
deleteItem: (index: number) => dispatch({ type: ActionTypesList.DeleteItem, payload: { index: index } })
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ListComponent);

View File

@ -1,18 +0,0 @@
import React from 'react';
// import logo from '../logo.svg';
import './InitialComponent.scss';
import { Link } from 'react-router-dom';
const OtherComponent = () => (
<div className="App">
<header className="App-header">
<img src="assets/img/logo.svg" className="App-logo" alt="logo" />
<p>
Edit <code>src/frontend/OtherComponent.jsx</code> and save to reload.
</p>
<Link className="App-link" to="/">Initial Component</Link>
</header>
</div>
);
export default OtherComponent;

View File

@ -4,7 +4,7 @@ import { useRoutes } from 'react-router-dom';
import routes from '../../routes';
const PrincipalRoutes = () => {
let element = useRoutes(routes);
const element = useRoutes(routes);
return element;
};

View File

@ -11,6 +11,6 @@ describe('Testing Card Component', () => {
);
});
it('Show Text', () => {
cy.get('p').contains('Edit src/frontend/InitialComponent.jsx and save to reload.');
cy.get('div').contains('List App');
});
});

View File

@ -4,20 +4,20 @@ import { ProviderMock } from '@mocks';
import App from '@components/App';
describe('<App/> Component', () => {
beforeEach(() => {
fetchMock.resetMocks();
});
beforeEach(() => {
fetchMock.resetMocks();
});
it('Should render root <App /> Component', async () => {
fetchMock.mockResponseOnce(JSON.stringify({
//First Data Fetch
data: 'data'
}));
it('Should render root <App /> Component', async () => {
fetchMock.mockResponseOnce(JSON.stringify({
//First Data Fetch
data: 'data'
}));
render(
<ProviderMock>
<App />
</ProviderMock>
)
})
})
render(
<ProviderMock>
<App />
</ProviderMock>
);
});
});

View File

@ -1,14 +1,14 @@
import { combineReducers } from 'redux';
import testReducer from './testReducer';
import { IChangeHelloPayload } from '../actions/testAction';
import listReducer from './listReducer';
import { TList } from '../actions/ListAction';
export interface IInitialState {
testReducer?: IChangeHelloPayload | undefined
listReducer?: TList | undefined
}
const rootReducer = combineReducers({
// Here comes the reducers
testReducer
listReducer
});
export default rootReducer;

View File

@ -0,0 +1,48 @@
import { ActionTypesList, TListAction, TItem, Status } from '../actions/ListAction';
const initialState = {
list: []
};
const listReducer = (state = initialState, action: TListAction) => {
switch (action.type){
case ActionTypesList.AddItem: {
const newList = [
...state.list,
action.payload.item
];
return {
list: newList
};
}
case ActionTypesList.ChangeStatus: {
const itemList = state.list[action.payload.index as number] as TItem;
const actualStatus = itemList.status;
const newItemList = {
...itemList,
status: actualStatus === Status.TODO ? Status.DONE : Status.TODO
};
const newList = [
...state.list.slice(0, action.payload.index as number),
newItemList,
...state.list.slice(action.payload.index as number + 1)
];
return {
list: newList
};
}
case ActionTypesList.DeleteItem: {
const newList = [
...state.list.slice(0, action.payload.index as number),
...state.list.slice(action.payload.index as number + 1)
];
return {
list: newList
};
}
default:
return state;
}
};
export default listReducer;

View File

@ -1,20 +0,0 @@
import { TAction } from '../actions';
const initialState = {
hello: 'world'
};
const testReducer = (state = initialState, action: TAction) => {
switch (action.type){
case 'CHANGE_HELLO': {
const newHello = action.payload.hello;
return {
hello: newHello
};
}
default:
return state;
}
};
export default testReducer;

View File

@ -1,4 +1,4 @@
$base-color: #282c34;
$base-color: #FFFFFF;
body {
background-color: $base-color;

View File

@ -1,15 +1,9 @@
import React from 'react';
import InitialComponent from '../frontend/components/InitialComponent';
import OtherComponent from '../frontend/components/OtherComponent';
const OTHER_COMPONENT = {
path: '/other-component',
element: <OtherComponent />
};
import List from '../frontend/components/List';
const INITIAL_COMPONENT = {
path: '/',
element: <InitialComponent />,
element: <List />,
};
export default [ INITIAL_COMPONENT, OTHER_COMPONENT ];
export default [ INITIAL_COMPONENT ];

View File

@ -43,7 +43,7 @@ func RegisterHandlers(e *echo.Echo, paths []string) {
<meta name="theme-color" content="#000000">
<!-- ${manifestJson} -->
<link href="assets/frontend.css" rel="stylesheet" type="text/css"></link>
<link href="assets/vendors.css" rel="stylesheet" type="text/css"></link>
<title>App</title>
</head>
<body>