├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ ├── CreateModal.vue
│ ├── EditModal.vue
│ ├── TaskItem.vue
│ ├── TaskList.vue
│ └── TaskListItem.vue
├── main.ts
├── shims-vue.d.ts
└── store
│ ├── actions.ts
│ ├── getters.ts
│ ├── index.ts
│ ├── mutations.ts
│ └── state.ts
└── tsconfig.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: false,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended',
9 | '@vue/typescript/recommended'
10 | ],
11 | parserOptions: {
12 | ecmaVersion: 2020
13 | },
14 | rules: {
15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vuex-ts-app
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vuex-ts-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "bulma": "^0.9.1",
12 | "core-js": "^3.6.5",
13 | "vue": "^3.0.0",
14 | "vuex": "^4.0.0-0"
15 | },
16 | "devDependencies": {
17 | "@typescript-eslint/eslint-plugin": "^2.33.0",
18 | "@typescript-eslint/parser": "^2.33.0",
19 | "@vue/cli-plugin-babel": "~4.5.0",
20 | "@vue/cli-plugin-eslint": "~4.5.0",
21 | "@vue/cli-plugin-typescript": "~4.5.0",
22 | "@vue/cli-plugin-vuex": "~4.5.0",
23 | "@vue/cli-service": "~4.5.0",
24 | "@vue/compiler-sfc": "^3.0.0",
25 | "@vue/eslint-config-typescript": "^5.0.2",
26 | "eslint": "^6.7.2",
27 | "eslint-plugin-vue": "^7.0.0-0",
28 | "typescript": "~3.9.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emmanuelhashy/vue3-task-manager/5134f3c70a18f146f180230adccb5f033b6c22dc/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
26 | Vue 3 Task Management App with Typescript and Vuex 4
27 |
28 |
29 |
30 |
Loading...
31 |
32 |
33 |
34 | {{ completedCount }} of {{ totalCount }} completed.
35 |
36 |
37 |
38 |
39 |
40 |
43 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emmanuelhashy/vue3-task-manager/5134f3c70a18f146f180230adccb5f033b6c22dc/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/CreateModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
69 |
70 |
119 |
--------------------------------------------------------------------------------
/src/components/EditModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
63 |
64 |
69 |
70 |
71 |
141 |
--------------------------------------------------------------------------------
/src/components/TaskItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
VIEW TASK
6 |
7 |
8 |
15 |
16 |
Description: {{ task.description }}
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
54 |
--------------------------------------------------------------------------------
/src/components/TaskList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Task Id |
6 | Completed |
7 | Task |
8 | Created By |
9 | Assigned To |
10 | Actions |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
61 |
73 |
--------------------------------------------------------------------------------
/src/components/TaskListItem.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ id }} |
3 |
4 |
5 | |
6 | {{ title }} (C) |
7 | {{ createdBy }} |
8 | {{ assignedTo }} |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | |
20 |
21 |
67 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import {store} from './store'
4 |
5 | createApp(App).use(store).mount('#app')
6 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import type { DefineComponent } from 'vue'
3 | const component: DefineComponent<{}, {}, any>
4 | export default component
5 | }
6 |
--------------------------------------------------------------------------------
/src/store/actions.ts:
--------------------------------------------------------------------------------
1 | import { ActionContext, ActionTree } from 'vuex'
2 | import { Mutations, MutationType } from './mutations'
3 | import { State } from './state'
4 |
5 | export enum ActionTypes {
6 | GetTaskItems = 'GET_Task_ITEMS',
7 | SetCreateModal = 'SET_CREATE_MODAL',
8 | SetEditModal = 'SET_EDIT_MODAL'
9 | }
10 |
11 | type ActionAugments = Omit, 'commit'> & {
12 | commit(
13 | key: K,
14 | payload: Parameters[1]
15 | ): ReturnType;
16 | }
17 |
18 |
19 | export type Actions = {
20 | [ActionTypes.GetTaskItems](context: ActionAugments): void;
21 | [ActionTypes.SetCreateModal](context: ActionAugments): void;
22 | [ActionTypes.SetEditModal](context: ActionAugments): void;
23 |
24 | }
25 |
26 | const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
27 |
28 | export const actions: ActionTree & Actions = {
29 | async [ActionTypes.GetTaskItems]({ commit }) {
30 | commit(MutationType.SetLoading, true)
31 |
32 | await sleep(1000)
33 |
34 | commit(MutationType.SetLoading, false)
35 | commit(MutationType.SetTasks, [
36 | {
37 | id: 1,
38 | title: 'Create a new programming language',
39 | description: "The programing language should have full typescript support ",
40 | createdBy: "Emmanuel John",
41 | assignedTo: "Saviour Peter",
42 | completed: false,
43 | editing: false
44 |
45 | }
46 | ])
47 | },
48 |
49 | async [ActionTypes.SetCreateModal]({ commit }) {
50 | commit(MutationType.SetCreateModal, true)
51 | },
52 | async [ActionTypes.SetEditModal]({ commit }) {
53 | commit(MutationType.SetEditModal, {showModal: true, taskId: 1})
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/store/getters.ts:
--------------------------------------------------------------------------------
1 | import { GetterTree } from 'vuex'
2 | import { State, TaskItem } from './state'
3 |
4 | export type Getters = {
5 | completedTaskCount(state: State): number
6 | totalTaskCount(state: State): number
7 | getTaskById(state: State): (id :number) => TaskItem | undefined
8 | }
9 |
10 | export const getters: GetterTree & Getters = {
11 | completedTaskCount(state) {
12 | return state.tasks.filter(element => element.completed).length
13 | },
14 | totalTaskCount(state) {
15 | return state.tasks.length
16 | },
17 | getTaskById: (state) => (id: number) => {
18 | return state.tasks.find(task => task.id === id)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createStore,
3 | Store as VuexStore,
4 | CommitOptions,
5 | DispatchOptions,
6 | createLogger
7 | } from 'vuex'
8 |
9 | import { State, state } from './state'
10 | import { Mutations, mutations } from './mutations'
11 | import { Actions, actions } from './actions'
12 | import { Getters, getters } from './getters'
13 |
14 | export const store = createStore({
15 | plugins: process.env.NODE_ENV === 'development' ? [createLogger()] : [],
16 | state,
17 | mutations,
18 | actions,
19 | getters
20 | })
21 |
22 | export function useStore() {
23 | return store as Store
24 | }
25 |
26 | export type Store = Omit<
27 | VuexStore,
28 | 'getters' | 'commit' | 'dispatch'
29 | > & {
30 | commit[1]>(
31 | key: K,
32 | payload: P,
33 | options?: CommitOptions
34 | ): ReturnType;
35 | } & {
36 | dispatch(
37 | key: K,
38 | payload?: Parameters[1],
39 | options?: DispatchOptions
40 | ): ReturnType;
41 | } & {
42 | getters: {
43 | [K in keyof Getters]: ReturnType
44 | };
45 | }
--------------------------------------------------------------------------------
/src/store/mutations.ts:
--------------------------------------------------------------------------------
1 | import { MutationTree } from 'vuex'
2 | import { State, TaskItem } from './state'
3 |
4 | export enum MutationType {
5 | CreateTask = 'CREATE_TASK',
6 | SetTasks = 'SET_TASKS',
7 | CompleteTask = 'COMPLETE_TASK',
8 | RemoveTask = 'REMOVE_TASK',
9 | EditTask = 'EDIT_TASK',
10 | UpdateTask = `UPDATE_TASK`,
11 |
12 | SetLoading = 'SET_LOADING',
13 | SetCreateModal = 'SET_CREATE_MODAL',
14 | SetEditModal = 'SET_EDIT_MODAL',
15 | SetTaskModal = 'SET_TASK_MODAL'
16 | }
17 |
18 | export type Mutations = {
19 |
20 | [MutationType.CreateTask](state: State, task: TaskItem): void;
21 | [MutationType.SetTasks](state: State, tasks: TaskItem[]): void;
22 | [MutationType.CompleteTask](
23 | state: State,
24 | task: Partial & { id: number }
25 | ): void;
26 | [MutationType.RemoveTask](
27 | state: State,
28 | task: Partial & { id: number }
29 | ): void;
30 | [MutationType.EditTask](
31 | state: State,
32 | task: Partial & { id: number }
33 | ): void;
34 | [MutationType.UpdateTask](
35 | state: State,
36 | task: Partial & { id: number }
37 | ): void;
38 |
39 | [MutationType.SetLoading](state: State, value: boolean): void;
40 | [MutationType.SetCreateModal](state: State, value: boolean): void;
41 | [MutationType.SetEditModal](state: State, value: {showModal: boolean, taskId: number|undefined}): void;
42 | [MutationType.SetTaskModal](state: State, value: {showModal: boolean, taskId: number|undefined}): void;
43 | };
44 |
45 | export const mutations: MutationTree & Mutations = {
46 | [MutationType.CreateTask](state, task) {
47 | state.tasks.unshift(task)
48 | },
49 | [MutationType.SetTasks](state, tasks) {
50 | state.tasks = tasks
51 | },
52 | [MutationType.CompleteTask](state, newTask) {
53 | const task = state.tasks.findIndex(element => element.id === newTask.id)
54 | if (task === -1) return
55 | state.tasks[task] = { ...state.tasks[task], ...newTask }
56 | },
57 | [MutationType.RemoveTask](state, Task) {
58 | const task = state.tasks.findIndex(element => element.id === Task.id)
59 | if (task === -1) return
60 | //If Task exist in the state, remove it
61 | state.tasks.splice(task, 1)
62 | },
63 | [MutationType.EditTask](state, Task) {
64 | const task = state.tasks.findIndex(element => element.id === Task.id)
65 | if (task === -1) return
66 | //If Task exist in the state, toggle the editing property
67 | state.tasks[task] = { ...state.tasks[task], editing: !state.tasks[task].editing }
68 | console.log("taskino", state.tasks[task])
69 | },
70 | [MutationType.UpdateTask](state, Task) {
71 | state.tasks = state.tasks.map(task => {
72 | if(task.id === Task.id) {
73 | return {...task, ...Task}
74 | }
75 | return task;
76 | })
77 | },
78 |
79 | [MutationType.SetLoading](state, value) {
80 | state.loading = value
81 | console.log("I am loading...")
82 | },
83 | [MutationType.SetCreateModal](state, value) {
84 | state.showCreateModal = value
85 | },
86 | [MutationType.SetEditModal](state, value) {
87 | state.showEditModal = value.showModal
88 | state.editModalTaskId = value.taskId
89 | },
90 | [MutationType.SetTaskModal](state, {showModal, taskId}) {
91 | state.showTaskModal = showModal
92 | state.showTaskId = taskId
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/store/state.ts:
--------------------------------------------------------------------------------
1 | export type TaskItem = {
2 | id: number;
3 | title: string;
4 | description: string;
5 | createdBy: string;
6 | assignedTo: string;
7 | completed: boolean;
8 | editing: boolean;
9 | };
10 |
11 | export type State = {
12 | loading: boolean;
13 | tasks: TaskItem[];
14 | showCreateModal: boolean;
15 | showEditModal: boolean;
16 | showTaskModal: boolean;
17 | editModalTaskId: number | undefined;
18 | showTaskId: number | undefined;
19 | };
20 |
21 | export const state: State = {
22 | loading: false,
23 | tasks: [],
24 | showCreateModal: false,
25 | showEditModal: false,
26 | showTaskModal: false,
27 | editModalTaskId: undefined,
28 | showTaskId: undefined,
29 | };
30 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "skipLibCheck": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "webpack-env"
16 | ],
17 | "paths": {
18 | "@/*": [
19 | "src/*"
20 | ]
21 | },
22 | "lib": [
23 | "esnext",
24 | "dom",
25 | "dom.iterable",
26 | "scripthost"
27 | ]
28 | },
29 | "include": [
30 | "src/**/*.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "tests/**/*.ts",
34 | "tests/**/*.tsx"
35 | ],
36 | "exclude": [
37 | "node_modules"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------