From b93495c05acf84b5557f77e0396d747bb4f0238d Mon Sep 17 00:00:00 2001
From: LeeYongJae <sdc5678@ajou.ac.kr>
Date: Mon, 9 Dec 2019 13:50:30 +0900
Subject: [PATCH] =?UTF-8?q?Transaction=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?=
 =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8,=20=ED=9A=8C=EC=9B=90=EA=B0=80?=
 =?UTF-8?q?=EC=9E=85=20validate=20=EC=A0=81=EC=9A=A9,=20backend=20api=20?=
 =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EC=A0=95=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/models/Book.js                        |  31 ----
 backend/routes/books.js                       |  46 ------
 backend/routes/emails.js                      |   4 +
 backend/routes/login.js                       |  27 ++--
 backend/routes/transaction.js                 | 135 +++++++++++++---
 frontend/package-lock.json                    |   5 +
 frontend/package.json                         |   3 +-
 frontend/src/components/BookSearchPage.vue    |  16 +-
 frontend/src/components/Buy.vue               |  84 ++++------
 frontend/src/components/Sell.vue              |  32 ++--
 .../src/components/home_hotlist/Hotlist.vue   |  25 +--
 frontend/src/components/login/Login.vue       |  93 +++++++++--
 frontend/src/components/login/SignUp.vue      | 147 +++++++++++++++---
 frontend/src/components/mainpage.vue          |   5 +-
 .../components/profilecomponent/buylist.vue   | 105 +++++++++----
 .../components/profilecomponent/sellist.vue   | 105 +++++++++----
 frontend/src/router/index.js                  |  16 --
 17 files changed, 548 insertions(+), 331 deletions(-)

diff --git a/backend/models/Book.js b/backend/models/Book.js
index 9756ebe..38d9357 100644
--- a/backend/models/Book.js
+++ b/backend/models/Book.js
@@ -9,40 +9,9 @@ const BookSchema = new Schema({
   major: { type: String },
   type: { type: String },
   src: { type: String },
-  seller: [
-    {
-      seller_id: { type: String },
-      on_transaction: { type: Boolean }
-    }
-  ],
-
   stock: { type: Number }
 });
 
-BookSchema.statics.create = function(Book_info) {
-  const {
-    title,
-    grade,
-    major,
-    type,
-    src,
-    stock,
-    seller: []
-  } = Book_info;
-
-  const Book = new this({
-    title,
-    grade,
-    major,
-    type,
-    src,
-    stock,
-    seller: []
-  });
-  // return the Promise
-  return Book.save();
-};
-
 autoInc.initialize(mongoose.connection);
 BookSchema.plugin(autoInc.plugin, "Book");
 
diff --git a/backend/routes/books.js b/backend/routes/books.js
index 93d3421..4026b74 100644
--- a/backend/routes/books.js
+++ b/backend/routes/books.js
@@ -1,8 +1,5 @@
 var express = require("express");
 var router = express.Router();
-var fs = require("fs");
-var path = require("path");
-var User = require("../models/user");
 var Book = require("../models/Book");
 
 // 梨� 紐⑸줉 遺덈윭�ㅺ린
@@ -28,47 +25,4 @@ router.get("/:id", function(req, res) {
   });
 });
 
-// 梨� 異붽�
-router.post("/", function(req, res) {
-  console.log("Post start");
-  const Book_info = req.body;
-
-  Book.create(Book_info)
-    .then(result => {
-      if (result) res.json({ result: true });
-      else res.json({ result: false });
-    })
-    .catch(function(error) {
-      console.log(error);
-    });
-});
-
-// 梨� 援щℓ 諛� �먮ℓ
-router.post("/:id", function(req, res) {
-  Book.findById(req.params.id, function(err, book) {
-    if (err) {
-      console.error(err);
-      return;
-    }
-    console.log(req.body.userId);
-    if (req.body.isBuyer === true) {
-      // var soldbook = book.seller.shift();
-      // book.stock--;
-      // book.save();
-      console.log(book.seller);
-      var temp = book.seller.find(element => element.on_transaction === false);
-      // book.seller.find(
-      //   element => element.on_transaction === false
-      // ).on_transaction = true;
-      // book.save();
-      res.json({ result: temp });
-      return;
-    }
-    book.seller.push({ seller_id: req.body.userId, on_transaction: false });
-    book.stock++;
-    book.save();
-    res.json({ result: true });
-  });
-});
-
 module.exports = router;
diff --git a/backend/routes/emails.js b/backend/routes/emails.js
index da0be3c..77ff923 100644
--- a/backend/routes/emails.js
+++ b/backend/routes/emails.js
@@ -8,6 +8,9 @@ router.post("/", function(req, res, next) {
   let bookTitle = req.body.bookTitle;
   let buyerPhoneNumber = req.body.buyerPhoneNumber;
 
+  console.log(sellerEmail);
+  console.log(bookTitle);
+  console.log(buyerPhoneNumber);
   let transporter = nodemailer.createTransport({
     service: "gmail",
     auth: {
@@ -33,6 +36,7 @@ router.post("/", function(req, res, next) {
       console.log(error);
     } else {
       console.log("Email sent: " + info.response);
+      res.send({ result: 1 });
     }
   });
 });
diff --git a/backend/routes/login.js b/backend/routes/login.js
index 1b4447f..80e20cb 100644
--- a/backend/routes/login.js
+++ b/backend/routes/login.js
@@ -68,19 +68,26 @@ router.get("/getUserId", function(req, res) {
   }
 });
 
-router.post("/getUserInfo", function(req, res) {
+router.post("/getUserInfo", async (req, res) => {
   console.log("getUserInfo start");
-  var getInfoId = req.body.userId;
-  console.log(getInfoId);
-  User.findOne({ id: getInfoId }, function(err, user) {
-    if (err) {
-      res.send(err);
+  var getBuyerInfoId = req.body.buyerId;
+  var getSellerInfoId = req.body.sellerId;
+
+  try {
+    const buyer = await User.findOne({ id: getBuyerInfoId });
+    const seller = await User.findOne({ id: getSellerInfoId });
+
+    if (!buyer) {
+      return res.status(404).json({ error: "Buyer not found" });
     }
-    if (!user) {
-      return res.status(404).json({ error: "user not found" });
+    if (!seller) {
+      return res.status(404).json({ error: "seller not found" });
     }
-    res.json(user);
-  });
+
+    res.json({ buyer: buyer, seller: seller });
+  } catch (err) {
+    res.json({ error: err.message });
+  }
 });
 
 module.exports = router;
diff --git a/backend/routes/transaction.js b/backend/routes/transaction.js
index ad402d3..d657063 100644
--- a/backend/routes/transaction.js
+++ b/backend/routes/transaction.js
@@ -1,6 +1,8 @@
 const express = require("express");
 const router = express.Router();
 const Transaction = require("../models/transaction");
+const User = require("../models/user");
+const Book = require("../models/Book");
 
 router.get("/", function(req, res) {
   console.log("Get transaction start");
@@ -13,24 +15,121 @@ router.get("/", function(req, res) {
   });
 });
 
-router.post("/", function(req, res) {
-  console.log("Post transaction start");
-  var transaction = new Transaction();
-  transaction.buyerId = req.body.buyerId;
-  console.log(req.body.buyerId);
-  transaction.sellerId = req.body.sellerId;
-  console.log(req.body.sellerId);
-  transaction.bookTitle = req.body.bookTitle;
-  transaction.on_transaction = true;
-
-  transaction.save(function(err) {
-    if (err) {
-      console.error(err);
-      res.json({ result: 0 });
-      return;
-    }
-    res.json({ result: 1 });
-  });
+router.post("/cancel", async (req, res) => {
+  console.log("POST - cancel start");
+  var sess = req.session;
+  var req_bookTitle = req.body.bookTitle;
+  var userId = sess.userid;
+
+  try {
+    await Transaction.findOne(
+      {
+        bookTitle: req_bookTitle,
+        $or: [{ buyerId: userId }, { sellerId: userId }]
+      },
+      function(err, transaction) {
+        if (err) {
+          console.error(err);
+          return;
+        }
+        transaction.buyerId = "";
+        transaction.on_transaction = false;
+        transaction.save();
+        res.json({ result: true });
+      }
+    );
+  } catch (err) {
+    res.json({ error: err.message });
+  }
+});
+
+router.post("/success", async (req, res) => {
+  console.log("POST - success start");
+  var sess = req.session;
+  var req_bookTitle = req.body.bookTitle;
+  var userId = sess.userid;
+
+  try {
+    await Transaction.remove(
+      {
+        bookTitle: req_bookTitle,
+        $or: [{ buyerId: userId }, { sellerId: userId }]
+      },
+      function(err, transaction) {
+        if (err) {
+          console.error(err);
+          return;
+        }
+        Book.findOne({ title: req_bookTitle }, function(err, book) {
+          if (err) {
+            console.error(err);
+            return;
+          }
+          book.stock--;
+          book.save();
+        });
+        // transaction.on_transaction = "";
+        // transaction.save();
+        res.json({ result: true });
+      }
+    );
+  } catch (err) {
+    res.json({ error: err.message });
+  }
+});
+
+router.post("/buy", async (req, res) => {
+  console.log("POST - buy start");
+  var sess = req.session;
+  var req_bookTitle = req.body.bookTitle;
+  buyerId = sess.userid;
+
+  try {
+    await Transaction.findOne({ bookTitle: req_bookTitle }, function(
+      err,
+      transaction
+    ) {
+      if (err) {
+        console.error(err);
+        return;
+      }
+      transaction.buyerId = buyerId;
+      transaction.on_transaction = true;
+      transaction.save();
+      res.json({ buyerId: buyerId, sellerId: transaction.sellerId });
+    });
+  } catch (err) {
+    res.json({ error: err.message });
+  }
+});
+
+router.post("/sell", async (req, res) => {
+  console.log("POST - sell start");
+  var sess = req.session;
+  var bookTitle = req.body.bookTitle;
+  sellerId = sess.userid;
+  console.log(sellerId);
+
+  try {
+    await Book.findOne({ title: bookTitle }, function(err, book) {
+      if (err) {
+        console.error(err);
+        return;
+      }
+
+      var transaction = new Transaction();
+      transaction.sellerId = sellerId;
+      transaction.buyerId = "";
+      transaction.bookTitle = book.title;
+      transaction.on_transaction = false;
+      book.stock++;
+      transaction.save();
+      book.save();
+      res.json({ result: true });
+    });
+  } catch (err) {
+    res.json({ error: err.message });
+  }
 });
 
 module.exports = router;
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 25cd8f7..448b3aa 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11802,6 +11802,11 @@
       "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
       "dev": true
     },
+    "vuelidate": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/vuelidate/-/vuelidate-0.7.4.tgz",
+      "integrity": "sha512-QHZWYOL325Zo+2K7VBNEJTZ496Kd8Z31p85aQJFldKudUUGBmgw4zu4ghl4CyqPwjRCmqZ9lDdx4FSdMnu4fGg=="
+    },
     "vuetify": {
       "version": "2.1.11",
       "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.1.11.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index d38d1cf..d611624 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,7 +15,8 @@
     "vue": "^2.5.2",
     "vue-material": "^1.0.0-beta-11",
     "vue-multiselect": "^2.1.6",
-    "vue-router": "^3.0.1"
+    "vue-router": "^3.0.1",
+    "vuelidate": "^0.7.4"
   },
   "devDependencies": {
     "autoprefixer": "^7.1.2",
diff --git a/frontend/src/components/BookSearchPage.vue b/frontend/src/components/BookSearchPage.vue
index 1aea237..2f2e00d 100644
--- a/frontend/src/components/BookSearchPage.vue
+++ b/frontend/src/components/BookSearchPage.vue
@@ -94,7 +94,7 @@
         </md-field>
         <md-dialog-actions>
           <md-button class="md-primary" v-on:click="active = false">Close</md-button>
-          <md-button class="md-primary" v-on:click="Register">Submit</md-button>
+          <md-button class="md-primary">Submit</md-button>
         </md-dialog-actions>
       </md-dialog>
       <!-- ============================================== -->
@@ -139,23 +139,11 @@ export default {
       this.Books = response.data;
       console.log("Success");
       console.log(this.Books);
-
     });
   },
   methods: {
     Search: function() {
-        this.SearchResult = true;  
-    },
-    Register() {
-      this.$http
-        .post("/api/books", this.submit)
-        .then(res => {
-          console.log("Submit Success");
-        })
-        .catch(err => {
-          console.log("Submit failed");
-        });
-      this.active = false;
+      this.SearchResult = true;
     },
     goBuyPage(bookId) {
       this.$router.push({ name: "BookSearchPageBuy", params: { id: bookId } });
diff --git a/frontend/src/components/Buy.vue b/frontend/src/components/Buy.vue
index 9515470..2e0c107 100644
--- a/frontend/src/components/Buy.vue
+++ b/frontend/src/components/Buy.vue
@@ -66,71 +66,43 @@ export default {
   },
   methods: {
     buyBook() {
-      this.$http.get("/api/login/getUserId").then(response => {
-        console.log("rd" + response.data);
-        this.userId = response.data;
-        var id = this.$route.params.id;
-        console.log("user:" + this.userId);
-        this.$http
-          .post(`/api/books/${id}`, {
-            userId: this.userId,
-            isBuyer: true
-          })
-          .then(
-            res => {
-              console.log(res.data);
-              this.sellerId = res.data.result.seller_id;
-              this.$http
-                .post("/api/transaction", {
-                  buyerId: this.userId,
-                  sellerId: this.sellerId,
-                  bookTitle: this.book.title
-                })
-                .then(response => {
-                  console.log("buy.vue-transaction post");
-                  alert("援щℓ�� �깃났�섏��듬땲��. �먮ℓ�먯뿉寃� 硫붿씪�� 蹂대깄�덈떎.");
-                  this.sendEmail();
-                });
-            },
-            error => {
-              alert(error.response.data.error);
-            }
-          )
-          .catch(error => {
-            alert(error);
-          });
-      });
-    },
-    sendEmail() {
-      console.log("sendEmail start");
       this.$http
-        .post("/api/login/getUserInfo", {
-          userId: this.userId // buyer
+        .post("/api/transaction/buy", {
+          bookTitle: this.book.title
         })
         .then(response => {
-          this.buyer = response.data;
+          alert("援щℓ�� �깃났�섏��듬땲��. �먮ℓ�먯뿉寃� 硫붿씪�� 蹂대깄�덈떎.");
+          this.buyerId = response.data.buyerId;
+          this.sellerId = response.data.sellerId;
+          this.sendEmail();
+        })
+        .catch(error => {
+          alert(error);
         });
-
+    },
+    sendEmail() {
+      console.log("sendEmail start");
       this.$http
         .post("/api/login/getUserInfo", {
-          userId: this.sellerId
+          buyerId: this.buyerId, // buyer
+          sellerId: this.sellerId
         })
         .then(response => {
-          this.seller = response.data;
+          this.buyer = response.data.buyer;
+          this.seller = response.data.seller;
+          this.$http
+            .post("/api/emails", {
+              sellerEmail: this.seller.email,
+              bookTitle: this.book.title,
+              buyerPhoneNumber: this.buyer.phonenumber
+            })
+            .then(response => {
+              alert("�대찓�� �꾩넚 �꾨즺");
+            }),
+            error => {
+              alert(error.response.data.error);
+            };
         });
-
-      this.$http
-        .post("/api/emails", {
-          sellerEmail: this.seller.email,
-          bookTitle: this.book.title,
-          buyerPhoneNumber: this.buyer.phonenumber
-        })
-        .then(response => {
-          alert("�대찓�� �꾩넚 �꾨즺");
-        }),
-        error => {
-          alert(error.response.data.error);
-        };
     }
   }
 };
diff --git a/frontend/src/components/Sell.vue b/frontend/src/components/Sell.vue
index 7c1bcc8..ae27fd1 100644
--- a/frontend/src/components/Sell.vue
+++ b/frontend/src/components/Sell.vue
@@ -63,28 +63,16 @@ export default {
   },
   methods: {
     sellBook() {
-      this.$http.get("/api/login/getUserId").then(response => {
-        console.log("rd" + response.data);
-        this.userId = response.data;
-        var id = this.$route.params.id;
-        console.log("user:" + this.userId);
-        this.$http
-          .post(`/api/books/${id}`, {
-            userId: this.userId
-          })
-          .then(
-            response => {
-              alert("�먮ℓ ��湲곗뿴�� �깅줉�섏��듬땲��.");
-              //this.$router.push("home");
-            },
-            error => {
-              alert(error.response.data.error);
-            }
-          )
-          .catch(error => {
-            alert(error);
-          });
-      });
+      this.$http
+        .post("/api/transaction/sell", {
+          bookTitle: this.book.title
+        })
+        .then(response => {
+          alert("�먮ℓ ��湲곗뿴�� �깅줉�섏��듬땲��.");
+        })
+        .catch(error => {
+          alert(error);
+        });
     }
   }
 };
diff --git a/frontend/src/components/home_hotlist/Hotlist.vue b/frontend/src/components/home_hotlist/Hotlist.vue
index 53c2b65..4e60974 100644
--- a/frontend/src/components/home_hotlist/Hotlist.vue
+++ b/frontend/src/components/home_hotlist/Hotlist.vue
@@ -1,7 +1,6 @@
 <template>
   <div>
     <md-table v-model="users" md-sort="title" md-sort-order="asc" md-card md-fixed-header>
-
       <md-table-row slot="md-table-row" slot-scope="{ item }" style="margin-top:100px">
         <md-table-cell md-label="�ш퀬" md-sort-by="stock" md-numeric>
           {{
@@ -19,13 +18,12 @@
           }}
         </md-table-cell>
         <md-table-cell>
-          <md-button class="md-primary md-raised">援щℓ</md-button>
+          <md-button class="md-primary md-raised" v-on:click="goBuyPage(item._id)">援щℓ</md-button>
         </md-table-cell>
         <md-table-cell>
-          <md-button class="md-raised md-accent">�먮ℓ</md-button>
+          <md-button class="md-raised md-accent" v-on:click="goSellPage(item._id)">�먮ℓ</md-button>
         </md-table-cell>
       </md-table-row>
-  
     </md-table>
   </div>
 </template>
@@ -45,25 +43,28 @@ const searchByName = (items, term) => {
 export default {
   name: "TableSearch",
   data: () => ({
-    users: [
-  
-    ]
+    users: []
   }),
   methods: {
+    goBuyPage(bookId) {
+      this.$router.push({ name: "HomeBuy", params: { id: bookId } });
+    },
+    goSellPage(bookId) {
+      this.$router.push({ name: "HomeSell", params: { id: bookId } });
+    }
   },
   created() {
-      this.$http.get("/api/books").then(response => {
+    this.$http.get("/api/books").then(response => {
       this.users = response.data;
       console.log("success");
       console.log(this.users);
-    
     });
   }
 };
 </script>
 
 <style lang="scss" scoped>
-  .md-field {
-    max-width: 500px;
-  }
+.md-field {
+  max-width: 500px;
+}
 </style>
diff --git a/frontend/src/components/login/Login.vue b/frontend/src/components/login/Login.vue
index a1faac8..6ed1512 100644
--- a/frontend/src/components/login/Login.vue
+++ b/frontend/src/components/login/Login.vue
@@ -1,43 +1,101 @@
 <template>
   <div id="login">
     <md-button class="md-primary" v-on:click="active = true">Login</md-button>
-    <md-dialog :md-active.sync="active" style="width: 500px; height: 500px">
-      <md-dialog-title>Login</md-dialog-title>
-      <md-field class="select">
-        <label>ID</label>
-        <md-input v-model="user.id" />
-      </md-field>
+    
+      <md-dialog :md-active.sync="active" style="width: 500px; height: 500px">
+        <md-dialog-title>Login</md-dialog-title>
+        <form novalidate @submit.prevent="validateUser">
+        <md-content>
+          <md-field :class="getValidationClass('id')">
+            <label>ID</label>
+            <md-input name="ID" id="ID" v-model="user.id" :disabled="sending" />
+            <span class="md-error" v-if="!$v.user.id.required">The ID is required"</span>
+            <span class="md-error" v-else-if="!$v.user.id.minlength"
+              >�꾩씠�붾뒗 �ㅼ꽢 �먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-field class="select">
-        <label>Password</label>
-        <md-input v-model="user.password" type="password" />
-      </md-field>
+          <md-field :class="getValidationClass('password')">
+            <label>Password</label>
+            <md-input v-model="user.password" type="password" :disabled="sending" />
+            <span class="md-error" v-if="!$v.user.password.required"
+              >The Password is required</span
+            >
+            <span class="md-error" v-else-if="!$v.user.password.minlength"
+              >鍮꾨�踰덊샇�� �� �먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-button class="md-raised md-primary" v-on:click="login">Login</md-button>
-      <md-button class="md-primary" v-on:click="active = false">Close</md-button>
-    </md-dialog>
+          <md-button
+            class="md-raised md-primary"
+            type="submit"
+            :disabled="sending"
+            >Login</md-button
+          >
+          <md-button class="md-primary" v-on:click="active = false"
+            >Close</md-button
+          >
+        </md-content>
+        </form>
+      </md-dialog>
+    </form>
   </div>
 </template>
 
 <script>
 import Vue from "vue";
+import Vuelidate from "vuelidate";
 import VueMaterial from "vue-material";
 import "vue-material/dist/vue-material.min.css";
 import "vue-material/dist/theme/default.css";
+import { validationMixin } from "vuelidate";
+import { required, minLength } from "vuelidate/lib/validators";
 Vue.use(VueMaterial);
+Vue.use(Vuelidate);
 
 export default {
+  name: "FormValidation",
+  mixins: [validationMixin],
   data: function() {
     return {
       active: false,
       user: {
-        id: "",
-        password: ""
-      }
+        id: null,
+        password: null
+      },
+      sending: false
     };
   },
+  validations: {
+    user: {
+      id: { 
+        required,
+        minLength: minLength(5)
+         }
+      ,
+      password: {
+        required,
+        minLength: minLength(3)
+      }
+    }
+  },
   methods: {
+    getValidationClass(fieldName) {
+      const field = this.$v.user[fieldName];
+      if (field) {
+        return {
+          "md-invalid": field.$invalid && field.$dirty
+        };
+      }
+    },
+    validateUser() {
+      this.$v.$touch();
+      if (!this.$v.$invalid) {
+        this.login();
+      }
+    },
     login: function(event) {
+      this.sending = true;
       console.log("login start");
       this.$http
         .post("/api/login/checkLogin", {
@@ -48,6 +106,7 @@ export default {
             //濡쒓렇�� �깃났
             alert("success login");
             this.active = false;
+            this.sending = false;
             location.reload();
           },
           error => {
@@ -63,7 +122,7 @@ export default {
 };
 </script>
 
-<style scoped>
+<style>
 .select {
   margin: 15px;
   display: inline-flex;
diff --git a/frontend/src/components/login/SignUp.vue b/frontend/src/components/login/SignUp.vue
index 958e483..77a9021 100644
--- a/frontend/src/components/login/SignUp.vue
+++ b/frontend/src/components/login/SignUp.vue
@@ -3,33 +3,91 @@
     <md-button class="md-primary" v-on:click="active = true">Sign Up</md-button>
     <md-dialog :md-active.sync="active" style="width:500px; height: 1000px">
       <md-dialog-title>Sign Up</md-dialog-title>
-      <md-field class="select">
-        <label>Name</label>
-        <md-input name="name" v-model="user.name" />
-      </md-field>
+      <form novalidate @submit.prevent="validateUser">
+        <md-content>
+          <md-field :class="getValidationClass('name')">
+            <label>Name</label>
+            <md-input name="name" v-model="user.name" :disabled="sending" />
+            <span class="md-error" v-if="!$v.user.name.required"
+              >The Name is required"</span
+            >
+            <span class="md-error" v-else-if="!$v.user.name.minlength"
+              >�대쫫�� �� �먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-field class="select">
-        <label for="id">ID</label>
-        <md-input name="id" v-model="user.id" />
-      </md-field>
+          <md-field :class="getValidationClass('id')">
+            <label for="id">ID</label>
+            <md-input name="id" v-model="user.id" :disabled="sending" />
+            <span class="md-error" v-if="!$v.user.id.required"
+              >The ID is required"</span
+            >
+            <span class="md-error" v-else-if="!$v.user.id.minlength"
+              >�꾩씠�붾뒗 �ㅼ꽢 �먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-field :md-toggle-password="true" class="select">
-        <label for="password">Password</label>
-        <md-input name="password" v-model="user.password" type="password" />
-      </md-field>
+          <md-field
+            :md-toggle-password="true"
+            :class="getValidationClass('password')"
+          >
+            <label for="password">Password</label>
+            <md-input
+              name="password"
+              v-model="user.password"
+              type="password"
+              :disabled="sending"
+            />
+            <span class="md-error" v-if="!$v.user.password.required"
+              >The Password is required</span
+            >
+            <span class="md-error" v-else-if="!$v.user.password.minlength"
+              >鍮꾨�踰덊샇�� �� �먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-field class="select">
-        <label for="email">Email</label>
-        <md-input name="email" v-model="user.email" />
-      </md-field>
+          <md-field :class="getValidationClass('email')">
+            <label for="email">Email</label>
+            <md-input
+              name="email"
+              type="email"
+              v-model="user.email"
+              :disabled="sending"
+            />
+            <span class="md-error" v-if="!$v.user.email.required"
+              >The email is required</span
+            >
+            <span class="md-error" v-else-if="!$v.user.email.email"
+              >Invalid email</span
+            >
+          </md-field>
 
-      <md-field class="select">
-        <label for="phonenumber">Phone Number</label>
-        <md-input name="phonenumber" v-model="user.phonenumber" />
-      </md-field>
+          <md-field :class="getValidationClass('phonenumber')">
+            <label for="phonenumber">Phone Number</label>
+            <md-input
+              name="phonenumber"
+              v-model="user.phonenumber"
+              :disabled="sending"
+            />
+            <span class="md-error" v-if="!$v.user.phonenumber.required"
+              >The Phone Number is required</span
+            >
+            <span class="md-error" v-else-if="!$v.user.phonenumber.minlength"
+              >�대��� 踰덊샇�� 10�먮━ �댁긽�댁뼱�� �⑸땲��.</span
+            >
+          </md-field>
 
-      <md-button class="md-raised md-primary" v-on:click="signUp">Sign Up</md-button>
-      <md-button class="md-primary" v-on:click="active = false">Close</md-button>
+          <md-button
+            class="md-raised md-primary"
+            type="submit"
+            :disabled="sending"
+            >Sign Up</md-button
+          >
+          <md-button class="md-primary" v-on:click="active = false"
+            >Close</md-button
+          >
+        </md-content>
+      </form>
     </md-dialog>
   </div>
 </template>
@@ -47,13 +105,17 @@
 
 <script>
 import Vue from "vue";
-
+import Vuelidate from "vuelidate";
 import VueMaterial from "vue-material";
 import "vue-material/dist/vue-material.min.css";
 import "vue-material/dist/theme/default.css";
+import { validationMixin } from "vuelidate";
+import { required, minLength, email } from "vuelidate/lib/validators";
 Vue.use(VueMaterial);
+Vue.use(Vuelidate);
 
 export default {
+  mixins: [validationMixin],
   data: function() {
     return {
       user: {
@@ -67,11 +129,48 @@ export default {
       active: false
     };
   },
+  validations: {
+    user: {
+      id: {
+        required,
+        minLength: minLength(5)
+      },
+      password: {
+        required,
+        minLength: minLength(3)
+      },
+      name: {
+        required,
+        minLength: minLength(2)
+      },
+      email: {
+        required,
+        email
+      },
+      phonenumber: {
+        required,
+        minLength: minLength(10)
+      }
+    }
+  },
   methods: {
+    getValidationClass(fieldName) {
+      const field = this.$v.user[fieldName];
+      if (field) {
+        return {
+          "md-invalid": field.$invalid && field.$dirty
+        };
+      }
+    },
+    validateUser() {
+      this.$v.$touch();
+      if (!this.$v.$invalid) {
+        this.signUp();
+      }
+    },
     signUp: function(event) {
       this.$http
         .post("/api/login/signUp", {
-          //axios �ъ슜
           user: this.user
         })
         .then(response => {
diff --git a/frontend/src/components/mainpage.vue b/frontend/src/components/mainpage.vue
index 4d4b1de..58bf9f3 100644
--- a/frontend/src/components/mainpage.vue
+++ b/frontend/src/components/mainpage.vue
@@ -4,7 +4,10 @@
       <div class="md-layout-item">
         <img src="../../static/img/img2.jpg" />
       </div>
-      <div class="md-layout-item" style="backgroundColor:#F2CB61; height:30px;">�댁쑄援�</div>
+      <div
+        class="md-layout-item"
+        style="backgroundColor:#F2CB61; height:30px;"
+      >2019 WebSysProject - Team 202</div>
     </div>
   </div>
 </template>
\ No newline at end of file
diff --git a/frontend/src/components/profilecomponent/buylist.vue b/frontend/src/components/profilecomponent/buylist.vue
index a53f69e..445931b 100644
--- a/frontend/src/components/profilecomponent/buylist.vue
+++ b/frontend/src/components/profilecomponent/buylist.vue
@@ -4,60 +4,105 @@
       <span>Buylist</span>
     </md-toolbar>
     <md-list class="md-double-line" style="height : 230px">
-      <md-list-item  v-for="user in users" :key="user.title">
+      <md-list-item
+        v-for="transaction in transactions"
+        :key="transaction._id"
+        v-if="transaction.buyerId == userId"
+      >
         <md-button class="md-icon-button md-raised" style="color:#1DDB16;backgroundColor:#1DDB16">
           <img src="../../assets/book-open-flat.png" />
         </md-button>
         <div class="md-list-item-text">
-          <span>&nbsp;&nbsp; {{user.title}}</span>
+          <span>&nbsp;&nbsp; {{transaction.bookTitle}}</span>
           <span>&nbsp;&nbsp;援щℓ ��湲곗쨷</span>
+          <span>&nbsp;&nbsp;�먮ℓ�� �꾩씠��: {{transaction.sellerId}}</span>
         </div>
-        <md-button class="md-icon-button md-raised md-accent">
+        <md-button
+          class="md-icon-button md-raised md-accent"
+          v-on:click="cancelTransaction(transaction.bookTitle)"
+        >
           <img src="../../assets/x-512.png" />
         </md-button>
-        <md-button class="md-icon-button md-raised md-primary">
+        <md-button
+          class="md-icon-button md-raised md-primary"
+          v-on:click="successTransaction(transaction.bookTitle)"
+        >
           <img src="../../assets/check-icon.png" />
         </md-button>
       </md-list-item>
     </md-list>
-
   </div>
 </template>
 
 <script>
-import Vue from 'vue'
-import VueMaterial from 'vue-material'
-import Multiselect from 'vue-multiselect'
-import 'vue-material/dist/vue-material.min.css'
-import 'vue-material/dist/theme/default.css'
-Vue.use(VueMaterial)
-  export default {
-  name: 'SubheaderExample',
+import Vue from "vue";
+import VueMaterial from "vue-material";
+import Multiselect from "vue-multiselect";
+import "vue-material/dist/vue-material.min.css";
+import "vue-material/dist/theme/default.css";
+Vue.use(VueMaterial);
+export default {
+  name: "SubheaderExample",
 
   data: () => ({
-    users: [],
+    transactions: [],
+    userId: ""
   }),
+  computed: {
+    // buyerTransaction() { - v-for�� computed �덉벐硫� 肄붾뱶 鍮④컙�됰맖, �묐룞�� ��
+    //   return this.transactions.filter(tran => {
+    //     if(this.buyerId === this.userId) {
+    //       return mov;
+    //     }
+    //   })
+    // }
+  },
   methods: {
-
+    cancelTransaction(book_Title) {
+      this.$http
+        .post("/api/transaction/cancel", {
+          bookTitle: book_Title
+        })
+        .then(response => {
+          alert("嫄곕옒瑜� 痍⑥냼�섏��듬땲��.");
+          location.reload();
+        })
+        .catch(error => {
+          alert(error);
+        });
+    },
+    successTransaction(book_Title) {
+      this.$http
+        .post("/api/transaction/success", {
+          bookTitle: book_Title
+        })
+        .then(response => {
+          alert("援щℓ瑜� �뺤씤�⑸땲��.");
+          location.reload();
+        })
+        .catch(error => {
+          alert(error);
+        });
+    }
   },
- 
-  mounted: function () {
-       this.$http.get("/api/books").then(response => {
-      this.users = response.data;
+
+  mounted: function() {
+    this.$http.get("/api/transaction").then(response => {
+      this.transactions = response.data;
       console.log("success");
-      console.log(this.users);
-    })
+      console.log(this.transactions);
+    });
+    this.$http.get("/api/login/getUserId").then(response => {
+      this.userId = response.data;
+    });
   }
-  }
-  
-
-  
+};
 </script>
 
 <style lang="scss" scoped>
-  .viewport {
-    width: 100%;
-    display: inline-block;
-    vertical-align: top;
-  }
+.viewport {
+  width: 100%;
+  display: inline-block;
+  vertical-align: top;
+}
 </style>
\ No newline at end of file
diff --git a/frontend/src/components/profilecomponent/sellist.vue b/frontend/src/components/profilecomponent/sellist.vue
index 938b929..cb05be6 100644
--- a/frontend/src/components/profilecomponent/sellist.vue
+++ b/frontend/src/components/profilecomponent/sellist.vue
@@ -4,60 +4,99 @@
       <span>Sellist</span>
     </md-toolbar>
     <md-list class="md-double-line" style="height : 230px">
-      <md-list-item  v-for="user in users" :key="user.title">
-        <md-button class="md-icon-button md-raised" style="color:#1DDB16;backgroundColor:#1DDB16">
+      <md-list-item
+        v-for="transaction in transactions"
+        :key="transaction._id"
+        v-if="transaction.sellerId == userId"
+      >
+        <md-button
+          class="md-icon-button md-raised"
+          style="color:#1DDB16;backgroundColor:#1DDB16"
+        >
           <img src="../../assets/book-open-flat.png" />
         </md-button>
         <div class="md-list-item-text">
-          <span>&nbsp;&nbsp; {{user.title}}</span>
-          <span>&nbsp;&nbsp;�먮ℓ ��湲�</span>
+          <span>&nbsp;&nbsp; {{ transaction.bookTitle }}</span>
+          <span>&nbsp;&nbsp;�먮ℓ ��湲곗쨷</span>
+          <span>&nbsp;&nbsp;援щℓ�� �꾩씠��: {{ transaction.buyerId }}</span>
         </div>
-        <md-button class="md-icon-button md-raised md-accent">
+        <md-button
+          class="md-icon-button md-raised md-accent"
+          v-on:click="cancelTransaction(transaction.bookTitle)"
+        >
           <img src="../../assets/x-512.png" />
         </md-button>
-        <md-button class="md-icon-button md-raised md-primary">
+        <md-button
+          class="md-icon-button md-raised md-primary"
+          v-on:click="successTransaction(transaction.bookTitle)"
+        >
           <img src="../../assets/check-icon.png" />
         </md-button>
       </md-list-item>
     </md-list>
-
   </div>
 </template>
 
 <script>
-import Vue from 'vue'
-import VueMaterial from 'vue-material'
-import Multiselect from 'vue-multiselect'
-import 'vue-material/dist/vue-material.min.css'
-import 'vue-material/dist/theme/default.css'
-Vue.use(VueMaterial)
-  export default {
-  name: 'SubheaderExample',
+import Vue from "vue";
+import VueMaterial from "vue-material";
+import Multiselect from "vue-multiselect";
+import "vue-material/dist/vue-material.min.css";
+import "vue-material/dist/theme/default.css";
+Vue.use(VueMaterial);
+export default {
+  name: "SubheaderExample",
 
   data: () => ({
-    users: [],
+    transactions: [],
+    userId: ""
   }),
   methods: {
-
+    cancelTransaction(book_Title) {
+      this.$http
+        .post("/api/transaction/cancel", {
+          bookTitle: book_Title
+        })
+        .then(response => {
+          alert("嫄곕옒瑜� 痍⑥냼�섏��듬땲��.");
+          location.reload();
+        })
+        .catch(error => {
+          alert(error);
+        });
+    },
+    successTransaction(book_Title) {
+      this.$http
+        .post("/api/transaction/success", {
+          bookTitle: book_Title
+        })
+        .then(response => {
+          alert("�먮ℓ瑜� �뺤씤�⑸땲��.");
+          location.reload();
+        })
+        .catch(error => {
+          alert(error);
+        });
+    }
   },
- 
-  mounted: function () {
-       this.$http.get("/api/books").then(response => {
-      this.users = response.data;
+
+  mounted: function() {
+    this.$http.get("/api/transaction").then(response => {
+      this.transactions = response.data;
       console.log("success");
-      console.log(this.users);
-    })
+      console.log(this.transactions);
+    });
+    this.$http.get("/api/login/getUserId").then(response => {
+      this.userId = response.data;
+    });
   }
-  }
-  
-
-  
+};
 </script>
 
 <style lang="scss" scoped>
-  .viewport {
-    width: 100%;
-    display: inline-block;
-    vertical-align: top;
-  }
-</style>
\ No newline at end of file
+.viewport {
+  width: 100%;
+  display: inline-block;
+  vertical-align: top;
+}
+</style>
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index 4c3e913..f63caab 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -24,7 +24,6 @@ export default new Router({
       name: "home",
       component: home
     },
-
     {
       path: "/profile",
       name: "profile",
@@ -35,21 +34,6 @@ export default new Router({
       name: "bookindex",
       component: BookSearchPage
     },
-    {
-      path: "/login",
-      name: "Login",
-      component: Login
-    },
-    {
-      path: "/logout",
-      name: "Logout",
-      component: Logout
-    },
-    {
-      path: "/signUp",
-      name: "SignUp",
-      component: SignUp
-    },
     {
       path: "/BookSearchPage/buy/:id",
       name: "BookSearchPageBuy",
-- 
GitLab