Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/UI bug #576

Merged
merged 7 commits into from
Oct 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
File renamed without changes.
60 changes: 60 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Architecture

[実装クリーンアーキテクチャ](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8)を踏まえて、twinte-front では以下のアーキテクチャは以下を採用しています。

![Architecture image](https://user-images.githubusercontent.com/68944024/161409877-375bb674-b668-4388-9df6-ddd081b9581f.png)

### 1. Entity

ビジネスロジックを表現するためのオブジェクトです。

### 2. UseCase

「このソフトウェアは何ができるのか?」を表現します。

### 3. IRepository

`UseCase`の`Port`を示します。`UseCase`を使用するためのルールのようなものです。

### 4. Repository

データの永続化を行います。`IRepository`の要件さえ満たしていれば、データベースでも、ローカルストレージでも実装方法は問いません。

### 5. Presenter

`ViewModel`と`Entity`の相互変換を行います。

### 6. ViewModel

UI のための型です。`View`で使用されます。

### 7. View

画面の描画を担当します。

# State Management

[Vue.js/State Management](https://vuejs.org/guide/scaling-up/state-management.html)を参考に twinte-front で採用している状態管理について解説します。

`View`を描画するためには、その元となる唯一の情報源が必要で、`State`と呼ばれています。また、ユーザーが`View`から何らかの入力をした場合に、`Action`が呼び出され、`State`を変更することができます。そして、`State`が変更されると`View`は更新されます。この単方向のデータフローを図に示すと以下のようになります。

![Data Flow](https://user-images.githubusercontent.com/68944024/161410858-c3dfca15-2645-4ec5-a7ae-14590462f8b7.png)

## Example

例えば、授業詳細画面でメモの更新を行うときは以下のような処理が行われます。

1. `State` をもとに `View` が描画されている
2. メモの更新を行うため `View` から `Action` を呼び出す(ex. `updateMemo`)
3. `Action` から `UseCase` を呼び出す(ex. `updateRegisteredCrouse`)
4. 更新された `ViewModel` を取得するため `Action` から `Presenter` を呼び出す(ex. `createViewModelCourse`)
5. `State` を 4 で取得した `ViewModel` に更新する
6. `State` が変更されたため `View` が更新される

# References

- [実装クリーンアーキテクチャ](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8)
- [Vue.js/State Management](https://vuejs.org/guide/scaling-up/state-management.html)
- [Twin:te backend v2](https://github.com/twin-te/twinte-server)
- [frontend-clean-architecture](https://github.com/bespoyasov/frontend-clean-architecture/tree/master/src)
- [flux](https://facebook.github.io/flux/docs/in-depth-overview)
7 changes: 5 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta
name="description"
content="筑波大学生専用の時間割アプリTwin:te(ついんて)です"
Expand All @@ -21,6 +24,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/src/ui/main.ts"></script>
</body>
</html>
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"typecheck": "vue-tsc --noEmit",
"build": "yarn typecheck && vite build",
"build:staging": "vite build --mode staging",
"preview": "yarn build && vite preview --port 8080",
"format": "prettier ./src --check",
"format:fix": "prettier ./src --write",
"lint": "eslint --ext .ts,.tsx,.vue ./src",
Expand All @@ -22,6 +23,7 @@
"@gtm-support/vue-gtm": "^1.3.0",
"@sentry/browser": "^6.2.5",
"@sentry/tracing": "^6.2.5",
"@types/lodash": "^4.14.184",
"@types/qs": "^6.9.6",
"@unocss/reset": "^0.31.2",
"@vueuse/core": "^4.6.2",
Expand All @@ -30,6 +32,7 @@
"axios": "^0.21.1",
"dayjs": "^1.10.4",
"firebase": "^8.3.2",
"lodash": "^4.17.21",
"qs": "^6.10.1",
"vue": "^3.0.9",
"vue-router": "4",
Expand Down
61 changes: 0 additions & 61 deletions src/App.vue

This file was deleted.

48 changes: 38 additions & 10 deletions src/adapter/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import { ConfigType, Dayjs } from "dayjs";
import { Store } from "vuex";
import { ApiInstance } from "~/api/$api";
import { GlobalState } from "~/store";

export interface Ports {
api: ApiInstance;
store: Store<GlobalState>;
dayjs: (date?: ConfigType) => Dayjs;
}
import { Ports } from "~/application/ports";
import { CalendarRepositoryInMemory } from "~/repositories/development/CalendarRepositoryInMemory";
import { CourseRepositoryInMemory } from "~/repositories/development/CourseRepositoryInMemory";
import { FeedbackRepositoryInMemory } from "~/repositories/development/FeedbackRepositoryInMemory";
import { NewsRepositoryInMemory } from "~/repositories/development/NewsRepositoryInMemory";
import { UserRepositoryInMemory } from "~/repositories/development/UserRepositoryInMemory";
import { CalendarRepository } from "~/repositories/production/CalendarRepository";
import { CourseRepository } from "~/repositories/production/CourseRepository";
import { FeedbackRepository } from "~/repositories/production/FeedbackRepository";
import { NewsRepository } from "~/repositories/production/NewsRepository";
import { UserRepository } from "~/repositories/production/UserRepository";

const dev = false;
let ports: Ports | undefined = undefined;

export const usePorts = (): Ports => {
if (ports) return ports;

if (dev) {
ports = {
calendarRepository: new CalendarRepositoryInMemory(),
courseRepository: new CourseRepositoryInMemory(),
feedbackRepository: new FeedbackRepositoryInMemory(),
newsRepository: new NewsRepositoryInMemory(),
userRepository: new UserRepositoryInMemory(),
};
} else {
ports = {
calendarRepository: new CalendarRepository(),
courseRepository: new CourseRepository(),
feedbackRepository: new FeedbackRepository(),
newsRepository: new NewsRepository(),
userRepository: new UserRepository(),
};
}

return ports;
};
Loading