Skip to content

Commit

Permalink
Refactoring/frontend recoil mvvm (#90)
Browse files Browse the repository at this point in the history
* Added recoil and major refactoring

* Fixed add todo

* Added css

* Fixed login logout

* Working version

* Completed TodoViewModel with Recoil integration

* Fixed all issues and added eslint
  • Loading branch information
danias authored Aug 1, 2023
1 parent 1a75c2f commit 5387984
Show file tree
Hide file tree
Showing 83 changed files with 9,264 additions and 9,210 deletions.
9 changes: 9 additions & 0 deletions frontend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*/proto/*
/src/bitloops/proto/*
*/src/bitloops/proto/*
/src/bitloops/proto/todo.ts
*/src/bitloops/proto/todo.ts
/src/bitloops/proto/todo_pb.d.ts
*/src/bitloops/proto/todo_pb.d.ts
/src/bitloops/proto/TodoServiceClient_Pb.ts
*/src/bitloops/proto/TodoServiceClient_Pb.ts
63 changes: 63 additions & 0 deletions frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"env": {
"browser": true,
"es2021": true
},
"extends": [
"airbnb",
"airbnb-typescript",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"prettier"
],
"overrides": [
{
"extends": [],
"files": [
"*.ts",
"*.tsx"
]
}
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": [
"react",
"jsx-a11y",
"react-hooks",
"@typescript-eslint",
"prettier"
],
"rules": {
"prettier/prettier": "error",
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error"],
"react/function-component-definition": "off",
"react/jsx-filename-extension": [1, { "extensions": [".tsx", ".ts"] }],
"react/react-in-jsx-scope": "off",
"class-methods-use-this": "off",
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "never",
"tsx": "never",
"js": "never",
"jsx": "never"
}
],
"quotes": ["error", "single"],
"@typescript-eslint/quotes": ["error", "single"],
"no-underscore-dangle": "off"
}
}
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# dependencies
/node_modules
node_modules
/.pnp
.pnp.js

Expand Down
9 changes: 9 additions & 0 deletions frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*/proto/*
/src/bitloops/proto/*
*/src/bitloops/proto/*
/src/bitloops/proto/todo.ts
*/src/bitloops/proto/todo.ts
/src/bitloops/proto/todo_pb.d.ts
*/src/bitloops/proto/todo_pb.d.ts
/src/bitloops/proto/TodoServiceClient_Pb.ts
*/src/bitloops/proto/TodoServiceClient_Pb.ts
7 changes: 6 additions & 1 deletion frontend/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"singleQuote": true
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"trailingComma": "es5"
}
7 changes: 7 additions & 0 deletions frontend/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
2 changes: 1 addition & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:19-alpine
FROM node:19-alpine
# Set the working directory to /app inside the container
WORKDIR /app
# Copy app files
Expand Down
28 changes: 28 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo

You should not need to run it directly from this folder as it is part of the docker build file but if you want to run it locally for development you can follow the instructions below at "Available Scripts".

## Web App Design

The web app is using a flavour of the MVVM (Model-View-View Model) pattern. You should be aware of the following ideas:

### Components

Here we have simple React code combined with imports of CSS files for the formatting. These components do not have state and you could inject anything you like through the props to test them.

### Controllers

A controller wraps a Component and maps the functions and values coming from a View Model (see below). You might have the occasional useState for maybe an [open, setOpen] value but nothing more.

### State

For state Recoil is being used but the state interacts with the ViewModel and should not be directly accessed or mutated from the Controllers with the exception of the App.tsx file that sets the setters and getters in the View Models.

### View Models

A View Model is a class that has a clearly defined interface that provides controllers with all the necessary functions and values to feed to their Components. We are utilizing the concept of CQRS meaning that we have separate functions that cause side-effects (aka mutations) and separate values that work like queries.

### Repositories

Repositories are used to interact with the app state (e.g. localStorage) and the Services (see below). For example, a service expects some authentication metadata (JWT) with the requests and instead of complicating the ViewModel with these details, a Repository provides a cleaner interface to the ViewModel for using the Services by taking care of the JWT injection etc. You can also use Repositories to deal with local caching etc.

### Services

Services are the gRPC endpoints that are automatically generated by the protobuf file and you could also add other services to wrap 3rd party API calls (e.g. Google Maps API).

## Technologies Used

To communicate with the backend, grpc-web is being used for the main functionality while a couple REST requests are used for registration and login.
Expand Down
64 changes: 49 additions & 15 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
{
"name": "todo-frontend",
"version": "0.1.1",
"version": "0.2.0",
"private": true,
"dependencies": {
"axios": "^1.3.5",
"@chakra-ui/icons": "^2.1.0",
"@chakra-ui/react": "^2.8.0",
"@chakra-ui/system": "^2.6.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@grpc/grpc-js": "^1.8.21",
"eventemitter3": "^5.0.1",
"framer-motion": "^10.15.0",
"google-protobuf": "^3.21.2",
"grpc-web": "^1.4.2",
"jwt-decode": "^3.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.8.0"
"react-icons": "^4.8.0",
"react-router-dom": "^6.14.2",
"recoil": "^0.7.7",
"source-map-loader": "^4.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"proto": "protoc -I=. src/bitloops/proto/todo.proto --js_out=import_style=commonjs,binary:. --grpc-web_out=import_style=typescript,mode=grpcwebtext:.",
"proto": "protoc -I=. src/bitloops/proto/todo.proto --ts_out=. --ts_opt=target=web,json_names,unary_rpc_promise=true,no_namespace --grpc-web_out=import_style=typescript,mode=grpcwebtext:.",
"docker:build": "docker build -t todo-frontend .",
"docker:run": "docker run -dp 3000:3000 --name todo-frontend todo-frontend",
"docker": "docker build -t todo-frontend . && docker run -dp 3000:3000 --name todo-frontend todo-frontend"
"docker": "docker build -t todo-frontend . && docker run -dp 3000:3000 --name todo-frontend todo-frontend",
"postinstall": "patch-package",
"lint": "eslint ."
},
"eslintConfig": {
"extends": [
Expand All @@ -39,16 +52,37 @@
]
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^29.5.0",
"@types/node": "^18.15.11",
"@types/react": "^18.0.34",
"@types/react-dom": "^18.0.11",
"protoc-gen-grpc-web": "^1.4.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",

"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@typescript-eslint/eslint-plugin": ">=6.0.0",
"@typescript-eslint/parser": ">=6.0.0",
"eslint": ">=8.0.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^8.9.0",
"eslint-config-xo": "^0.43.1",
"eslint-config-xo-typescript": "^1.0.1",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^3.0.0",

"react-scripts": "5.0.1",
"typescript": "^5.0.4",
"web-vitals": "^3.3.1"
"typescript": ">=4.7",
"web-vitals": "^2.1.0",

"@types/google-protobuf": "^3.15.6",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
"protoc-gen-grpc-web": "^1.4.2"
}
}
15 changes: 15 additions & 0 deletions frontend/patches/grpc-web+1.4.2.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
diff --git a/node_modules/grpc-web/index.d.ts b/node_modules/grpc-web/index.d.ts
index 09fb671..9b6b233 100644
--- a/node_modules/grpc-web/index.d.ts
+++ b/node_modules/grpc-web/index.d.ts
@@ -71,8 +71,8 @@ declare module "grpc-web" {
export class MethodDescriptor<REQ, RESP> {
constructor(name: string,
methodType: string,
- requestType: new (...args: unknown[]) => REQ,
- responseType: new (...args: unknown[]) => RESP,
+ requestType: new (...args: any) => REQ,
+ responseType: new (...args: any) => RESP,
requestSerializeFn: any,
responseDeserializeFn: any);
getName(): string;
101 changes: 0 additions & 101 deletions frontend/src/App.css

This file was deleted.

Loading

0 comments on commit 5387984

Please sign in to comment.