├── .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 | 40 | 43 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelhashy/vue3-task-manager/5134f3c70a18f146f180230adccb5f033b6c22dc/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/CreateModal.vue: -------------------------------------------------------------------------------- 1 | 70 | 119 | -------------------------------------------------------------------------------- /src/components/EditModal.vue: -------------------------------------------------------------------------------- 1 | 71 | 141 | -------------------------------------------------------------------------------- /src/components/TaskItem.vue: -------------------------------------------------------------------------------- 1 | 28 | 54 | -------------------------------------------------------------------------------- /src/components/TaskList.vue: -------------------------------------------------------------------------------- 1 | 26 | 61 | 73 | -------------------------------------------------------------------------------- /src/components/TaskListItem.vue: -------------------------------------------------------------------------------- 1 | 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 | --------------------------------------------------------------------------------