From f047bcfcd85265b1c133f27ea2273ebf58f346df Mon Sep 17 00:00:00 2001
From: JunGu Kang <chr0m3.kr@gmail.com>
Date: Tue, 10 Dec 2019 06:04:18 +0900
Subject: [PATCH] #32 Refactor Program Views

Program Create View
Program Detail View
Program List View
---
 src/views/ProgramCreate.vue | 106 ++++++++++++-------------
 src/views/ProgramDetail.vue | 151 +++++++++++++++++------------------
 src/views/ProgramList.vue   | 153 ++++++++++++++++++------------------
 3 files changed, 204 insertions(+), 206 deletions(-)

diff --git a/src/views/ProgramCreate.vue b/src/views/ProgramCreate.vue
index 8923c23..d5cd0f1 100644
--- a/src/views/ProgramCreate.vue
+++ b/src/views/ProgramCreate.vue
@@ -1,60 +1,54 @@
 <template>
   <div class="program-detail">
-    <v-card
-      :loading="isProcessing"
-    >
-      <v-card-title>프로그램 생성</v-card-title>
-      <v-card-text>
-        <v-alert
-          v-if="error.isError"
-          dense
-          text
-          type="error"
-        >
-          {{ error.message }}
-        </v-alert>
-        <v-text-field
-          label="프로그램 이름"
-          v-model="program.title"
-        ></v-text-field>
-        <v-text-field
-          label="소요시간(분)"
-          v-model="program.durationTime"
-        ></v-text-field>
-        <v-textarea
-          auto-grow
-          label="프로그램 소개"
-          v-model="program.detail"
-        ></v-textarea>
-      </v-card-text>
-      <v-card-actions>
-        <v-spacer></v-spacer>
-        <v-btn
-          color="error"
-          outlined
-          @click="cancel"
-        >
-          <v-icon
-            left
-          >
-            mdi-delete
-          </v-icon>
-          취소
-        </v-btn>
-        <v-btn
-          color="primary"
-          outlined
-          @click="createProgram"
-        >
-          <v-icon
-            left
-          >
-            mdi-content-save
-          </v-icon>
-          저장
-        </v-btn>
-      </v-card-actions>
-    </v-card>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="isProcessing">
+          <v-card-title>프로그램 등록</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ error.message }}
+            </v-alert>
+            <v-text-field
+              label="프로그램 이름"
+              v-model="program.title"
+            ></v-text-field>
+            <v-text-field
+              label="소요시간(분)"
+              v-model="program.durationTime"
+            ></v-text-field>
+            <v-textarea
+              auto-grow
+              label="프로그램 소개"
+              v-model="program.detail"
+            ></v-textarea>
+          </v-card-text>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn
+              color="error"
+              outlined
+              @click="cancel"
+            >
+              <v-icon left>mdi-delete</v-icon>
+              취소
+            </v-btn>
+            <v-btn
+              color="primary"
+              outlined
+              @click="createProgram"
+            >
+              <v-icon left>mdi-content-save</v-icon>
+              저장
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
   </div>
 </template>
 
@@ -62,7 +56,7 @@
 import APISetting from '@/settings/api';
 
 export default {
-  name: 'ProgramDetail',
+  name: 'ProgramCreate',
 
   data: () => ({
     isProcessing: false,
diff --git a/src/views/ProgramDetail.vue b/src/views/ProgramDetail.vue
index f0a6ed1..d5309ab 100644
--- a/src/views/ProgramDetail.vue
+++ b/src/views/ProgramDetail.vue
@@ -1,79 +1,75 @@
 <template>
   <div class="program-detail">
-    <v-card
-      :loading="isProcessing"
-    >
-      <v-card-title>프로그램 정보</v-card-title>
-      <v-card-text>
-        <v-alert
-          v-if="error.isError"
-          dense
-          text
-          type="error"
-        >
-          {{ error.message }}
-        </v-alert>
-        <v-text-field
-          label="등록번호"
-          readonly
-          v-model="id"
-        ></v-text-field>
-        <v-text-field
-          label="프로그램 이름"
-          v-model="program.title"
-        ></v-text-field>
-        <v-text-field
-          label="소요시간(분)"
-          v-model="program.durationTime"
-        ></v-text-field>
-        <v-textarea
-          auto-grow
-          label="프로그램 소개"
-          v-model="program.detail"
-        ></v-textarea>
-        <v-text-field
-          label="등록 시각"
-          readonly
-          v-model="program.createdAt"
-        ></v-text-field>
-        <v-text-field
-          label="최종 수정 시각"
-          readonly
-          v-model="program.updatedAt"
-        ></v-text-field>
-      </v-card-text>
-      <v-card-actions>
-        <v-spacer></v-spacer>
-        <v-btn
-          color="error"
-          outlined
-          @click="deleteProgram(id)"
-        >
-          <v-icon
-            left
-          >
-            mdi-delete
-          </v-icon>
-          삭제
-        </v-btn>
-        <v-btn
-          color="primary"
-          outlined
-          @click="updateProgram(id)"
-        >
-          <v-icon
-            left
-          >
-            mdi-content-save
-          </v-icon>
-          저장
-        </v-btn>
-      </v-card-actions>
-    </v-card>
+    <v-row>
+      <v-col cols="12">
+        <v-card :loading="isProcessing">
+          <v-card-title>프로그램 정보</v-card-title>
+          <v-card-text>
+            <v-alert
+              v-if="error.isError"
+              dense
+              text
+              type="error"
+            >
+              {{ error.message }}
+            </v-alert>
+            <v-text-field
+              label="등록번호"
+              readonly
+              v-model="id"
+            ></v-text-field>
+            <v-text-field
+              label="프로그램 이름"
+              v-model="program.title"
+            ></v-text-field>
+            <v-text-field
+              label="소요시간(분)"
+              v-model="program.durationTime"
+            ></v-text-field>
+            <v-textarea
+              auto-grow
+              label="프로그램 소개"
+              v-model="program.detail"
+            ></v-textarea>
+            <v-text-field
+              label="등록 시각"
+              readonly
+              v-model="program.createdAt"
+            ></v-text-field>
+            <v-text-field
+              label="최종 수정 시각"
+              readonly
+              v-model="program.updatedAt"
+            ></v-text-field>
+          </v-card-text>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn
+              color="error"
+              outlined
+              @click="deleteProgram(id)"
+            >
+              <v-icon left>mdi-delete</v-icon>
+              삭제
+            </v-btn>
+            <v-btn
+              color="primary"
+              outlined
+              @click="updateProgram(id)"
+            >
+              <v-icon left>mdi-content-save</v-icon>
+              저장
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
   </div>
 </template>
 
 <script>
+import moment from 'moment';
+
 import APISetting from '@/settings/api';
 
 export default {
@@ -118,7 +114,10 @@ export default {
           const [json, res] = values;
           if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
           if (res.status !== 200) throw new Error(json.message);
-          this.program = json.program;
+          const { program } = json;
+          program.createdAt = moment(program.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          program.updatedAt = moment(program.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.program = program;
         })
         .catch((e) => {
           this.error.message = e.message;
@@ -136,14 +135,17 @@ export default {
       fetch(APISetting.endpoints.program.detail(id), APISetting.settings.put(this.program))
         .then((res) => {
           if (res.status === 404) return Promise.all([null, res]);
-          if ([200, 400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
+          if ([200, 400, 500].includes(res.status)) return Promise.all([res.json(), res]);
           throw new Error('알 수 없는 응답입니다.');
         })
         .then((values) => {
           const [json, res] = values;
           if (res.status === 404) throw new Error('존재하지 않는 데이터입니다.');
           if (res.status !== 200) throw new Error(json.message);
-          this.program = json.program;
+          const { program } = json;
+          program.createdAt = moment(program.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          program.updatedAt = moment(program.updatedAt).format('YYYY-MM-DD HH:mm:ss');
+          this.program = program;
         })
         .catch((e) => {
           this.error.message = e.message;
@@ -161,8 +163,7 @@ export default {
       fetch(APISetting.endpoints.program.detail(id), APISetting.settings.delete)
         .then((res) => {
           if ([204, 404].includes(res.status)) return Promise.all([null, res]);
-          if ([204, 400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
-          // If response status is not equal to 204, 400, 404, or 500, go to catch.
+          if ([400, 500].includes(res.status)) return Promise.all([res.json(), res]);
           throw new Error('알 수 없는 응답입니다.');
         })
         .then((values) => {
diff --git a/src/views/ProgramList.vue b/src/views/ProgramList.vue
index 4c22214..e119637 100644
--- a/src/views/ProgramList.vue
+++ b/src/views/ProgramList.vue
@@ -1,78 +1,78 @@
 <template>
   <div class="program-list">
-    <v-card>
-      <v-card-title>프로그램 목록</v-card-title>
-      <v-card-text>
-        <v-row
-          justify="end"
-        >
-          <v-col
-            align-self="center"
-            cols="12"
-            sm="8"
-            md="9"
-            lg="9"
-            xl="10"
-          >
-            <v-btn
-              color="success"
-              outlined
-              @click="createProgram"
-            >
-              <v-icon
-                left
+    <v-row>
+      <v-col cols="12">
+        <v-card>
+          <v-card-title>프로그램 목록</v-card-title>
+          <v-card-text>
+            <v-row>
+              <v-col
+                align-self="center"
+                cols="12"
+                sm="8"
+                md="9"
+                lg="9"
+                xl="10"
               >
-                mdi-plus
-              </v-icon>
-              새 프로그램 등록
-            </v-btn>
-          </v-col>
-          <v-col
-            cols="12"
-            sm="4"
-            md="3"
-            lg="3"
-            xl="2"
-          >
-            <v-text-field
-              append-icon="mdi-magnify"
-              clearable
-              label="프로그램 검색"
-              v-model="programList.searchKeyword"
-            ></v-text-field>
-          </v-col>
-        </v-row>
-        <v-data-table
-          :headers="programList.headers"
-          item-key="id"
-          :items="programList.data"
-          :loading="isProcessing"
-          loading-text="데이터를 불러오는 중입니다."
-          :search="programList.searchKeyword"
-          no-results-text="일치하는 프로그램을 찾지 못했습니다."
-        >
-          <template v-slot:item.action="{ item }">
-            <v-icon
-              small
-              class="mr-2"
-              @click="editProgram(item.id)"
-            >
-              mdi-pencil
-            </v-icon>
-            <v-icon
-              small
-              @click="deleteProgram(item.id)"
+                <v-btn
+                  color="success"
+                  outlined
+                  @click="createProgram"
+                >
+                  <v-icon left>mdi-plus</v-icon>
+                  새 프로그램 등록
+                </v-btn>
+              </v-col>
+              <v-col
+                cols="12"
+                sm="4"
+                md="3"
+                lg="3"
+                xl="2"
+              >
+                <v-text-field
+                  append-icon="mdi-magnify"
+                  clearable
+                  label="프로그램 검색"
+                  v-model="programList.searchKeyword"
+                ></v-text-field>
+              </v-col>
+            </v-row>
+            <v-data-table
+              :headers="programList.headers"
+              item-key="id"
+              :items="programList.data"
+              :loading="isProcessing"
+              loading-text="데이터를 불러오는 중입니다."
+              :search="programList.searchKeyword"
+              no-results-text="일치하는 프로그램을 찾지 못했습니다."
             >
-              mdi-delete
-            </v-icon>
-          </template>
-        </v-data-table>
-      </v-card-text>
-    </v-card>
+              <template v-slot:item.action="{ item }">
+                <v-icon
+                  small
+                  class="mr-2"
+                  @click="editProgram(item.id)"
+                >
+                  mdi-pencil
+                </v-icon>
+                <v-icon
+                  small
+                  @click="deleteProgram(item.id)"
+                >
+                  mdi-delete
+                </v-icon>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
+      </v-col>
+    </v-row>
   </div>
 </template>
 
 <script>
+import moment from 'moment';
+
 import APISetting from '@/settings/api';
 
 export default {
@@ -99,8 +99,8 @@ export default {
           value: 'durationTime',
         },
         {
-          text: '프로그램 소개',
-          value: 'detail',
+          text: '등록 시각',
+          value: 'createdAt',
         },
         {
           text: '',
@@ -122,11 +122,14 @@ export default {
       fetch(APISetting.endpoints.program.list, APISetting.settings.get)
         .then((res) => {
           if (res.status === 200) return res.json();
-          // If response status is not equal to 200, go to catch.
           throw new Error('알 수 없는 응답입니다.');
         })
         .then((json) => {
           this.programList.data = json.programs;
+          this.programList.data.forEach((program) => {
+            // eslint-disable-next-line no-param-reassign
+            program.createdAt = moment(program.createdAt).format('YYYY-MM-DD HH:mm:ss');
+          });
         })
         .catch((e) => {
           this.error.message = e.message;
@@ -145,25 +148,25 @@ export default {
     deleteProgram(id) {
       this.error.isError = false;
       this.error.message = '';
+      this.isProcessing = true;
 
       fetch(APISetting.endpoints.program.detail(id), APISetting.settings.delete)
         .then((res) => {
           if (res.status === 204) return Promise.all([null, res]);
-          if ([204, 400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
-          // If response status is not equal to 204, 400, 404, 500, go to catch.
+          if ([400, 404, 500].includes(res.status)) return Promise.all([res.json(), res]);
           throw new Error('알 수 없는 응답입니다.');
         })
         .then((values) => {
           const [json, res] = values;
-          // If program successfully deleted and response status is equal to 204,
-          // update program list.
           if (res.status === 204) return this.getProgramList();
-          // Otherwise, go to catch.
           throw new Error(json.message);
         })
         .catch((e) => {
           this.error.message = e.message;
           this.error.isError = true;
+        })
+        .finally(() => {
+          this.isProcessing = true;
         });
     },
   },
-- 
GitLab