4 Achegas 2e04f663de ... 76ba38f319

Autor SHA1 Mensaxe Data
  kiboky 76ba38f319 algoria 검색 기능 추가 %!s(int64=5) %!d(string=hai) anos
  kiboky dcc0aaf1f1 algoria 검색 API 추가 %!s(int64=5) %!d(string=hai) anos
  kiboky 43d8ffe088 검색엔진 algolia 설정 %!s(int64=5) %!d(string=hai) anos
  kiboky c6837eeda6 stripe 결제 추가 %!s(int64=5) %!d(string=hai) anos

+ 35 - 2
client/components/Search.vue

@@ -13,8 +13,20 @@
 
     <form novalidate="novalidate" onsubmit="return false;" class="searchbox sbx-amazon">
       <div role="search" class="sbx-amazon__wrapper">
-        <input type="search" name="search" placeholder="Search your Product" autocomplete="off" required="required" class="sbx-amazon__input">
-        <button type="submit" title="Submit your search query." class="sbx-amazon__submit">
+        <input
+          v-model="query"
+          type="search"
+          name="search"
+          placeholder="Search your Product"
+          autocomplete="off"
+          required="required"
+          class="sbx-amazon__input">
+        <button
+          @click="onSearch"
+          type="submit"
+          title="Submit your search query."
+          class="sbx-amazon__submit"
+        >
           <svg role="img" aria-label="Search">
             <use xlink:href="#sbx-icon-search-11"></use>
           </svg>
@@ -28,3 +40,24 @@
     </form>
   </div>
 </template>
+
+<script>
+export default {
+  data () {
+    return {
+      query: ''
+    }
+  },
+
+  methods: {
+    onSearch () {
+      this.$router.push({
+        path: '/search',
+        query: {
+          title: this.query
+        }
+      })
+    }
+  }
+}
+</script>

+ 405 - 0
client/pages/placeorder.vue

@@ -0,0 +1,405 @@
+<template>
+<body>
+  <!--SHIPPING ADDRESS-->
+  <div class="container-fluid">
+    <div class="shipping-address">
+      <div class="navbarShipping a-spacing-large">
+        <nuxt-link to="/">
+          <img src="img/placeHeadernav.gif" class="img-fluid" />
+        </nuxt-link>
+      </div>
+      <div class="a-row">
+        <div class="a-size-large a-text-bold a-spacing-mini">Review your order</div>
+        <div class="a-row a-spacing-small a-size-mini"></div>
+      </div>
+      <div class="row">
+        <div class="col-xl-9 col-lg-8 col-md-9 col-sm-12">
+          <div class="a-row a-spacing-large"></div>
+          <div class="spc-top a-box a-spacing-small">
+            <div class="a-box-inner">
+              <div class="row">
+                <div class="col-xl-4 col-lg-6 col-sm-6 col-6">
+                  <div class="a-spacing-base">
+                    <div class="a-row">
+                      <strong>
+                        Shipping address
+                        <small>
+                          <a href="#">Change</a>
+                        </small>
+                      </strong>
+                    </div>
+                    <div class="a-row">
+                      <div class="displayAddressDiv">
+                        <!-- User's address -->
+                        <ul class="displayAddressUL">
+                          <li>{{ $auth.$state.user.address.fullname }}</li>
+                          <li>{{ $auth.$state.user.address.streetAddress}}</li>
+                          <li>{{ $auth.$state.user.address.city }}</li>
+                          <li>{{ $auth.$state.user.address.country}}</li>
+                          <li>
+                            Phone:
+                            <span dir="ltr">{{ $auth.$state.user.address.phoneNumber}}</span>
+                          </li>
+                        </ul>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="col-xl-4 col-lg-6 col-sm-6 col-6">
+                  <div class="a-spacing-base">
+                    <div class="a-row">
+                      <strong>
+                        Payment Method
+                        <small>
+                          <a href="#">Change</a>
+                        </small>
+                      </strong>
+                    </div>
+                    <div class="a-row">
+                      <ul class="no-bullet-list">
+                        <li class="a-spacing-micro">
+                          <span class="a-list-item">
+                            <span>
+                              <img src="img/visa.gif" class="img-fluid" />
+                            </span>
+                            ending in
+                            <span>6397</span>
+                          </span>
+                        </li>
+                      </ul>
+                    </div>
+                  </div>
+                  <div class="a-row a-spacing-base">
+                    <div class="a-row">
+                      <strong>
+                        Billing Address
+                        <small>
+                          <a href="#">Change</a>
+                        </small>
+                      </strong>
+                    </div>
+                    <span>Same as shipping address</span>
+                  </div>
+                </div>
+                <div class="col-xl-4 col-lg-6 col-sm-12 col-12">
+                  <div class="a-spacing-base">
+                    <div class="a-spacing-mini">
+                      <span>
+                        <strong>Gift cards &amp; promotional codes</strong>
+                      </span>
+                    </div>
+                    <div class="row">
+                      <div class="col-xl-8 col-lg-7 col-md-7 col-sm-7 col-8 pr-0">
+                        <input
+                          type="text"
+                          autocomplete="off"
+                          class="a-input-text"
+                          placeholder="Enter Code"
+                        />
+                      </div>
+                      <div class="col-xl-4 col-lg-5 col-md-5 col-sm-5 col-4">
+                        <span class="a-buton-apply-code">
+                          <span class="a-button-inner">
+                            <span class="a-button-text">Apply</span>
+                          </span>
+                        </span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="spc-orders a-box">
+            <div class="a-box-inner">
+              <div class="shipping-group">
+                <!-- Estimated delivery -->
+                <div
+                  class="a-row a-color-state a-text-bold a-size-medium a-spacing-small"
+                >Estimated delivery: {{ estimatedDelivery }}</div>
+                <div class="row">
+                  <!-- Cart -->
+                  <div class="col-xl-6 col-lg-7 col-sm-6 col-12">
+                    <div v-for="product in getCart" :key="product._id" class="a-row a-spacing-base">
+                      <div class="row">
+                        <!-- Product's photo -->
+                        <div class="col-sm-3 col-3">
+                          <img :src="product.photo" style="width: 100px;" />
+                        </div>
+                        <!-- Product's Title -->
+                        <div class="col-sm-9 col-9">
+                          <div class="a-row">
+                            <strong>{{ product.title }}</strong>
+                          </div>
+                          <!-- Product's owner name -->
+                          <div class="a-row a-size-small">{{ product.owner.name }}</div>
+                          <div class="a-row">
+                            <!-- Product's price -->
+                            <span class="a-color-price a-spacing-micro">
+                              <strong dir="ltr">${{ product.price * product.quantity }}</strong>
+                            </span>
+                          </div>
+                          <div class="a-row">
+                            <span class="availability a-color-success">In Stock.</span>
+                          </div>
+                          <div class="a-row">
+                            <!-- Product's quantity -->
+                            <strong>Quantity: {{ product.quantity }}</strong>
+                          </div>
+                          <div
+                            class="a-row a-color-secondary a-size-small"
+                          >Sold by:&nbsp;Amazon.com Services, Inc</div>
+                          <div class="a-row">
+                            <div class="a-row a-spacing-top-micro">
+                              <span class="a-button-small">
+                                <span class="a-button-inner">
+                                  <i class="a-icon checkout-giftbox-icon"></i>
+                                  <a
+                                    href="#"
+                                    class="a-button-text gift-popover-link"
+                                  >Add a gift receipt</a>
+                                </span>
+                              </span>
+                            </div>
+                            <div class="a-row">
+                              <span class="a-color-secondary a-size-mini">and see other gift options</span>
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="col-xl-6 col-lg-5 col-sm-6 col-12">
+                    <div class="a-row shipping-speeds">
+                      <fieldset>
+                        <span class="shipping-speeds-title a-size-medium">
+                          <b>Choose a delivery option:</b>
+                        </span>
+                        <!-- Delivery option -->
+                        <div class="a-spacing-mini wednesday">
+                          <!-- Shipping normal -->
+                          <input @change="onChooseShipping('normal')" checked="checked" type="radio" name="order0" />
+                          <span class="a-radio-label">
+                            <span class="a-color-success">
+                              <strong>Averages 7 business days</strong>
+                            </span>
+                            <br />
+                            <span
+                              class="a-color-secondary"
+                            >$13.98&nbsp;-&nbsp;Standard International Shipping - No Tracking</span>
+                          </span>
+                        </div>
+                        <br />
+                        <div class="a-spacing-mini tuesday">
+                          <!-- Shipping fast -->
+                          <input @change="onChooseShipping('fast')" type="radio" name="order0" />
+                          <span class="a-radio-label">
+                            <span class="a-color-success">
+                              <strong>Averages 3 business days</strong>
+                            </span>
+                            <br />
+                            <span class="a-color-secondary">$49.98&nbsp;-&nbsp;Shipping</span>
+                          </span>
+                        </div>
+                      </fieldset>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="col-xl-3 col-lg-4 col-md-3 col-sm-12 pl-0">
+          <div class="a-box-group">
+            <div class="a-box a-first">
+              <div class="a-box-inner">
+                <div class="a-row a-spacing-micro">
+                  <nuxt-link to="/payment">
+                    <span class="a-button-place-order">Place your order in USD</span>
+                  </nuxt-link>
+                </div>
+                <div class="a-row a-spacing-small a-size-small a-text-center">
+                  By placing your order, you agree to Amazon's
+                  <a href="#">privacy notice</a>
+                  and
+                  <a href="#">conditions of use</a>.
+                </div>
+                <div class="a-row">
+                  <div id="tfx-header">
+                    <div class="a-box a-alert-info a-spacing-small">
+                      <div class="a-box-inner alert-info-no-icon">
+                        <strong>
+                          Amazon Currency Converter is Enabled. &nbsp;
+                          <a
+                            href="#"
+                            class="a-size-mini"
+                          >Learn More</a>
+                        </strong>
+                      </div>
+                    </div>
+                  </div>
+                  <h3 class="a-spacing-micro a-size-base">Order Summary</h3>
+                  <div class="order-summary" style="font-size: 12px;">
+                    <div class="row">
+                      <!-- Cart's total price -->
+                      <div class="col-sm-6">Items:</div>
+                      <div class="col-sm-6 text-right">USD ${{ getCartTotalPrice }}</div>
+                    </div>
+                    <div class="row">
+                      <!-- Shipping cost -->
+                      <div class="col-sm-6">Shipping & handling:</div>
+                      <div class="col-sm-6 text-right">USD {{ shippingPrice }}</div>
+                    </div>
+                    <div class="row mt-2">
+                      <div class="col-sm-6"></div>
+                      <div class="col-sm-6 text-right">
+                        <hr />
+                      </div>
+                    </div>
+                    <!-- Total Price with Shipping -->
+                    <div class="row">
+                      <div class="col-sm-6">Total Before Tax:</div>
+                      <div class="col-sm-6 text-right">USD {{ getCartTotalPriceWithShipping }}</div>
+                    </div>
+                    <div class="row">
+                      <div class="col-sm-6">Estimated tax to be collected:</div>
+                      <div class="col-sm-6 text-right">USD 0.00</div>
+                    </div>
+                    <hr />
+                    <div class="row">
+                      <div class="col-sm-6">
+                        <div class="a-color-price a-size-medium a-text-bold">Order total:</div>
+                      </div>
+                      <div class="col-sm-6 text-right">
+                        <!-- Total Price with Shipping -->
+                        <div class="a-color-price a-size-medium a-text-bold">USD {{ getCartTotalPriceWithShipping }}</div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="a-box a-last a-color-alternate-background">
+              <div class="a-box-inner">
+                <div class="a-spacing-base">
+                  <div class="a-row">
+                    <span>
+                      <i class="fas fa-caret-down"></i>
+                      <a href="#">Selected payment currency</a>
+                    </span>
+                    <fieldset class="pl-3">
+                      <span style="margin-left: 1rem;">
+                        <input type="radio" class="no-js-hide" value="transactional" />
+                        <span class="a-radio-label">USD</span>
+                      </span>
+                      <div class="a-row">
+                        <span class="a-size-mini">
+                          <a href="#">(Change card currency)</a>
+                        </span>
+                      </div>
+                    </fieldset>
+                  </div>
+                </div>
+                <div class="a-size-mini">
+                  <div class="a-row a-spacing-mini mb-1">
+                    Please note that your country may charge import duties, taxes and fees that you may have to pay ahead of delivery.
+                    <a
+                      href="#"
+                    >Learn more</a>
+                  </div>
+                  <div class="a-row a-spacing-mini mb-1">
+                    <a href="#">How are shipping costs calculated?</a>
+                  </div>
+                  <div class="a-row a-spacing-mini">
+                    <a href="#">Why didn't I qualify for free shipping?</a>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="a-row a-spacing-small a-spacing-top-small">
+        <p class="a-color-secondary a-size-mini">
+          Do you need help? Explore our
+          <a href="#">Help pages</a> or
+          <a href="#">contact us</a>
+        </p>
+        <p
+          class="a-color-secondary a-size-mini"
+        >For an item sold by Amazon.com: When you click the "Place your order" button, we'll send you an email message acknowledging receipt of your order. Your contract to purchase an item will not be complete until we send you an email notifying you that the item has been shipped.</p>
+        <p id="state-sales-tax-info" class="a-color-secondary a-size-mini">
+          Colorado, Oklahoma, South Dakota and Vermont Purchasers:
+          <a
+            href="#"
+          >Important information regarding sales tax you may owe in your State</a>
+        </p>
+        <div class="a-color-secondary a-size-mini">
+          <p class="a-color-secondary a-size-mini">
+            Within 30 days of delivery, you may return new, unopened merchandise in its original condition. Exceptions and restrictions apply. See Amazon.com's
+            <a
+              href="#"
+            >Returns Policy</a>
+            <br />
+            <br />Go to the
+            <a href="#">Amazon.com homepage</a> without completing your order.
+          </p>
+        </div>
+      </div>
+      <hr />
+      <p class="a-size-small a-text-center a-color-secondary" data-testid>
+        <a href="#">Conditions of Use</a> |
+        <a href="#">Privacy Notice</a> © 1996-2019, Amazon.com, Inc.
+      </p>
+    </div>
+  </div>
+  <!--/SHIPPING ADDRESS-->
+</body>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+export default {
+  layout: "none",
+  async asyncData ({ $axios, store }) {
+    try {
+      let response = await $axios.$post('/api/shipment', { shipment: 'normal' })
+
+      store.commit('setShipping', {
+        price: response.shipment.price,
+        estimatedDelivery: response.shipment.estimated
+      })
+
+      return {
+        shippingPrice: response.shipment.price,
+        estimatedDelivery: response.shipment.estimated
+      }
+    } catch (err) {
+
+    }
+
+  },
+  computed: {
+    ...mapGetters(['getCart', 'getCartTotalPrice', 'getCartTotalPriceWithShipping'])
+  },
+  methods: {
+    async onChooseShipping (shipment) {
+      try {
+        let response = await this.$axios.$post('/api/shipment', { shipment })
+
+        this.$store.commit('setShipping', {
+          price: response.shipment.price,
+          estimatedDelivery: response.shipment.estimated
+        })
+
+        this.shippingPrice = response.shipment.price,
+        this.estimatedDelivery = response.shipment.estimated
+
+      } catch (err) {
+
+      }
+    }
+
+  }
+};
+</script>

+ 148 - 0
client/pages/search.vue

@@ -0,0 +1,148 @@
+<template>
+  <main class="listingPage">
+    <div class="container-fluid">
+      <div class="row">
+        <div class="col-xl-2 col-lg-3 md-4 col-sm-4">
+          <!--SideBar -->
+        </div>
+        <!-- main content -->
+        <div class="col-xl-10 col-lg-9 md-8 col-sm-8">
+
+
+          <div class="mainResuts">
+            <div class="s-result-list">
+              <div v-for="product in products" :key="product._id" class="s-result-item celwidget">
+                <div class="s-item-container">
+                  <div class="a-spacing-micro">
+                    <div class="bestSeller">
+                      <a href="#">Best seller</a>
+                    </div>
+                  </div>
+
+                  <div>
+                    <div class="row">
+                      <!--image-->
+                      <div class="col-sm-3 text-center">
+                        <a href="">
+                          <img :src="product.photo" alt="" class="img-fluid" style="width: 150px">
+                        </a>
+                      </div>
+
+                      <div class="col-sm-9">
+                        <div class="a-row a-spacing-small">
+                          <!-- Title and date -->
+                          <nuxt-link :to="`/products/${product._id}`" class="a-link-normal">
+                            <h2 class="a-size-medium">
+                              {{ product.title }}
+                              <span class="a-letter-space"></span>
+                              <span class="a-letter-space"></span>
+                              <span class="a-size-small a-color-secondary">Sep 3, 2019</span>
+                            </h2>
+                          </nuxt-link>
+                        </div>
+
+                        <!--Author name -->
+                        <div class="a-row a-spacing-small">
+                          <span class="a-size-small a-color-secondary">by</span>
+                          <span class="a-size-small a-color-secondary">
+                            <a href="#" class="a-link-normal a-text-normal">{{ product.owner.name }}</a>
+                          </span>
+                        </div>
+
+                        <!--Author name -->
+                        <div class="a-row">
+                          <span class="a-size-small">Ships to USA</span>
+                        </div>
+
+                        <div class="row">
+                          <div class="col-sm-7">
+                            <div class="a-row a-spacing-none">
+                              <a href="#" class="a-link-normal a-text-normal">Hardcover</a>
+                            </div>
+
+                            <!-- price-->
+                            <div class="a-row a-spacing-none">
+                              <a href="" class="a-link-normal a-text-normal">
+                                <span class="a-offscreen">{{ product.price }}</span>
+                                <span class="a-color-base sx-zero-spacing">
+                                  <span class="sx-price sx-price-large">
+                                    <sup class="sx-price-currency">$</sup>
+                                    <span class="sx-price-wholsup">{{ product.price }}</span>
+                                    <sup class="sx-price-fractional">00</sup>
+                                  </span>
+                                </span>
+                              </a>
+                              <span class="a-letter-space"></span>
+                              <span class="a-size-base-plug a-color-secondary a-text-strike">$28.00</span>
+                            </div>
+
+                            <!-- Audible Trial -->
+                            <div class="a-row a-spacing-none">
+                              <span class="a-size-small a-color-secondary">Free wuith trial </span>
+                            </div>
+                            <hr/>
+
+                            <!-- Other Format -->
+                            <span class="a-size-small a-color-secondray">
+                              other form
+                              <span class="a-letter-space"></span>
+                              <a href="" class="a-size-small a-linkl-normal a-text-normal">Audio CD</a>
+                            </span>
+
+                            <!-- Ratiings -->
+                            <div class="col-sm-5">
+                              <div class="a-row a-spacing-mini">
+                                <!-- star rating -->
+                                <no-ssr>
+                                  <star-rating
+                                    :rating="product.averageRating"
+                                    :show-rating="false"
+                                    :glow="1"
+                                    :border-width="1"
+                                    :rounded-corners="true"
+                                    :read-only="true"
+                                    :star-size="18"
+                                    :star-points="[23,2,14,17,0,19,10,34,7,50,23,43,38,50,36,34,46,19,31,17]"
+                                  ></star-rating>
+                                </no-ssr>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+
+                      </div>
+                    </div>
+                  </div>
+
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </main>
+</template>
+
+<script>
+import StarRating from 'vue-star-rating'
+
+export default {
+  components: {
+    StarRating
+  },
+  watchQuery: ['title'],
+
+  async asyncData ({ $axios, query }) {
+    try {
+      let products = await $axios.$post('/api/search', { title: query.title })
+
+      return {
+        products
+      }
+    } catch (err) {
+
+    }
+  }
+}
+</script>

+ 16 - 1
client/store/index.js

@@ -1,6 +1,9 @@
 export const state = () => ({
   cart: [],
-  cartLength: 0
+  cartLength: 0,
+  price: 0,
+  shippingPrice:0,
+  estimatedDelivery: ''
 })
 
 export const actions = {
@@ -57,6 +60,11 @@ export const mutations = {
     state.cartLength -= product.quantity
     let indexOfProduct = state.cart.indexOf(product)
     state.cart.splice(indexOfProduct, 1)
+  },
+
+  setShipping (state, { price, estimatedDelivery }) {
+    state.price = price
+    state.estimatedDelivery = estimatedDelivery
   }
 
 }
@@ -74,5 +82,12 @@ export const getters = {
       total += product.price * product.quantity
     })
     return total
+  },
+  getCartTotalPriceWithShipping (state) {
+    let total = 0
+    state.cart.map(product => {
+      total += product.price * product.quantity
+    })
+    return total + state.shippingPrice
   }
 }

+ 22 - 2
server/models/product.js

@@ -1,4 +1,5 @@
 const mongoose = require('mongoose')
+const mongooseAlgolia = require('mongoose-algolia')
 const Schema = mongoose.Schema
 
 const ProductSchema = new Schema({
@@ -18,7 +19,7 @@ const ProductSchema = new Schema({
 ProductSchema.virtual('averageRating').get(function () {
   if (this.reviews.length > 0) {
     let sum = this.reviews.reduce((total, review) => {
-      console.log('review', review)
+      // console.log('review', review)
       return total + review.rating
     }, 0)
     
@@ -28,4 +29,23 @@ ProductSchema.virtual('averageRating').get(function () {
   return 0
 })
 
-module.exports = mongoose.model('Product', ProductSchema)
+ProductSchema.plugin(mongooseAlgolia, {
+  appId: process.env.ALGOLIA_APP_ID,
+  apiKey: process.env.ALGOLIA_SECRET,
+  indexName: process.env.ALGOLIA_INDEX,
+  
+  selector: 'title _id photo description price rating averageRating owner',
+  populate: {
+    path: 'owner reviews'
+  },
+  debug: true
+})
+
+let Model = mongoose.model('Product', ProductSchema)
+Model.SyncToAlgolia()
+Model.SetAlgoliaSettings({
+  searchableAttributes: ['title']
+})
+
+module.exports = Model
+// module.exports = mongoose.model('Product', ProductSchema)

+ 293 - 0
server/package-lock.json

@@ -4,6 +4,11 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@types/node": {
+      "version": "13.1.6",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz",
+      "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg=="
+    },
     "accepts": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -13,6 +18,45 @@
         "negotiator": "0.6.2"
       }
     },
+    "agentkeepalive": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz",
+      "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8="
+    },
+    "algoliasearch": {
+      "version": "3.35.1",
+      "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz",
+      "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==",
+      "requires": {
+        "agentkeepalive": "^2.2.0",
+        "debug": "^2.6.9",
+        "envify": "^4.0.0",
+        "es6-promise": "^4.1.0",
+        "events": "^1.1.0",
+        "foreach": "^2.0.5",
+        "global": "^4.3.2",
+        "inherits": "^2.0.1",
+        "isarray": "^2.0.1",
+        "load-script": "^1.0.0",
+        "object-keys": "^1.0.11",
+        "querystring-es3": "^0.2.1",
+        "reduce": "^1.0.1",
+        "semver": "^5.1.0",
+        "tunnel-agent": "^0.6.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+          "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
+        }
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+    },
     "append-field": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@@ -126,6 +170,19 @@
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
       "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
     },
+    "cli-color": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz",
+      "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==",
+      "requires": {
+        "ansi-regex": "^2.1.1",
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "memoizee": "^0.4.14",
+        "timers-ext": "^0.1.5"
+      }
+    },
     "concat-stream": {
       "version": "1.6.2",
       "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
@@ -198,6 +255,15 @@
         "vary": "^1"
       }
     },
+    "d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "requires": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
     "debug": {
       "version": "2.6.9",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -206,6 +272,11 @@
         "ms": "2.0.0"
       }
     },
+    "deep-keys": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/deep-keys/-/deep-keys-0.4.0.tgz",
+      "integrity": "sha1-AimHC98UV7BUy/VUhOkvivWcvqs="
+    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -225,6 +296,11 @@
         "streamsearch": "0.1.2"
       }
     },
+    "dom-walk": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
+      "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
+    },
     "dotenv": {
       "version": "8.2.0",
       "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
@@ -248,16 +324,84 @@
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
     },
+    "envify": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz",
+      "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==",
+      "requires": {
+        "esprima": "^4.0.0",
+        "through": "~2.3.4"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.53",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
+      "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
+      "requires": {
+        "es6-iterator": "~2.0.3",
+        "es6-symbol": "~3.1.3",
+        "next-tick": "~1.0.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+    },
+    "es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "requires": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
+      }
+    },
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
     },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+    },
     "etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
     },
+    "event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
     "events": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
@@ -300,6 +444,21 @@
         "vary": "~1.1.2"
       }
     },
+    "ext": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
+      "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
+      "requires": {
+        "type": "^2.0.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz",
+          "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="
+        }
+      }
+    },
     "file-type": {
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
@@ -337,6 +496,11 @@
         }
       }
     },
+    "foreach": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+      "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
+    },
     "forwarded": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -347,6 +511,15 @@
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
     },
+    "global": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
+      "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
+      "requires": {
+        "min-document": "^2.19.0",
+        "process": "^0.11.10"
+      }
+    },
     "html-comment-regex": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
@@ -387,6 +560,11 @@
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
       "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
     },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+    },
     "is-svg": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
@@ -453,6 +631,11 @@
       "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
       "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
     },
+    "load-script": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
+      "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
+    },
     "lodash.includes": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@@ -488,11 +671,34 @@
       "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
       "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
     },
+    "lru-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+      "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
+      "requires": {
+        "es5-ext": "~0.10.2"
+      }
+    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
     },
+    "memoizee": {
+      "version": "0.4.14",
+      "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz",
+      "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==",
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.45",
+        "es6-weak-map": "^2.0.2",
+        "event-emitter": "^0.3.5",
+        "is-promise": "^2.1",
+        "lru-queue": "0.1",
+        "next-tick": "1",
+        "timers-ext": "^0.1.5"
+      }
+    },
     "memory-pager": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
@@ -527,6 +733,14 @@
         "mime-db": "1.42.0"
       }
     },
+    "min-document": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
+      "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
+      "requires": {
+        "dom-walk": "^0.1.0"
+      }
+    },
     "minimist": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
@@ -540,6 +754,11 @@
         "minimist": "0.0.8"
       }
     },
+    "moment": {
+      "version": "2.24.0",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
+    },
     "mongodb": {
       "version": "3.4.1",
       "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
@@ -576,6 +795,16 @@
         }
       }
     },
+    "mongoose-algolia": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/mongoose-algolia/-/mongoose-algolia-1.9.1.tgz",
+      "integrity": "sha512-lpQptDr2OnSjBV8OUNfGdqV4pVV41dP3ikZHTx9uBVXmvZXetOh29H6Smn7Z/OfpCRovrbNxwXD7mj8MdTtEgw==",
+      "requires": {
+        "algoliasearch": "^3.19.1",
+        "cli-color": "^1.1.0",
+        "deep-keys": "^0.4.0"
+      }
+    },
     "mongoose-legacy-pluralize": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
@@ -655,11 +884,21 @@
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
       "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
     },
+    "next-tick": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
+    },
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
+    },
     "on-finished": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -683,6 +922,11 @@
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
     },
+    "process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+    },
     "process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -712,6 +956,11 @@
       "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
       "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
     },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
+    },
     "range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -746,6 +995,14 @@
         }
       }
     },
+    "reduce": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.2.tgz",
+      "integrity": "sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ==",
+      "requires": {
+        "object-keys": "^1.1.0"
+      }
+    },
     "regexp-clone": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
@@ -876,11 +1133,47 @@
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
       "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
     },
+    "stripe": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/stripe/-/stripe-8.0.1.tgz",
+      "integrity": "sha512-0D9r1YGkrNFmX6RRk34P0uslrOw4cuav1yuJVcxlIwwhh8R06XIqTTPU6/PeGvJ89SUTU/+jny8gFZU0MZ0rpg==",
+      "requires": {
+        "@types/node": "^13.1.0",
+        "qs": "^6.6.0"
+      }
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
+    "timers-ext": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+      "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+      "requires": {
+        "es5-ext": "~0.10.46",
+        "next-tick": "1"
+      }
+    },
     "toidentifier": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
     },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+    },
     "type-is": {
       "version": "1.6.18",
       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",

+ 5 - 1
server/package.json

@@ -9,6 +9,7 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
+    "algoliasearch": "^3.35.1",
     "aws-sdk": "^2.596.0",
     "axios": "^0.19.1",
     "bcrypt-nodejs": "0.0.3",
@@ -17,9 +18,12 @@
     "dotenv": "^8.2.0",
     "express": "^4.17.1",
     "jsonwebtoken": "^8.5.1",
+    "moment": "^2.24.0",
     "mongoose": "^5.8.3",
+    "mongoose-algolia": "^1.9.1",
     "morgan": "^1.9.1",
     "multer": "^1.4.2",
-    "multer-s3": "^2.9.0"
+    "multer-s3": "^2.9.0",
+    "stripe": "^8.0.1"
   }
 }

+ 36 - 0
server/routes/payment.js

@@ -0,0 +1,36 @@
+const router = require('express').Router()
+const moment = require('moment')
+
+const SHIPMENT = {
+  normal: {
+    price: 13.98,
+    days: 7
+  },
+  fast: {
+    price: 49.98,
+    days: 3
+  }
+}
+
+function shipmentPrice (shipmentOption) {
+  let estimated = moment().add(shipmentOption.days, 'd').format('dddd MMMM Do')
+  return {
+    estimated,
+    price: shipmentOption.price
+  }
+}
+
+router.post('/shipment', (req, res) => {
+  let shipment;
+  if (req.body.shipment === 'normal') {
+    shipment = shipmentPrice(SHIPMENT.normal)
+  } else {
+    shipment = shipmentPrice(SHIPMENT.fast)
+  }
+
+  res.json({
+    success: true,
+    shipment
+  })
+})
+module.exports = router

+ 20 - 0
server/routes/search.js

@@ -0,0 +1,20 @@
+const router = require('express').Router()
+
+const algoliraSearch = require('algoliasearch')
+
+const client = algoliraSearch(
+  process.env.ALGOLIA_APP_ID,
+  process.env.ALGOLIA_SECRET,
+)
+
+const index = client.initIndex(process.env.ALGOLIA_INDEX)
+router.post('/search', async (req, res) => {
+  try {
+    let result  = await index.search(req.body.title)
+    res.json(result.hits)
+  } catch (err) {
+    res.json(err.message)
+  }
+})
+
+module.exports = router

+ 4 - 0
server/server.js

@@ -31,6 +31,8 @@ const ownerRouters = require('./routes/owner')
 const userRouters = require('./routes/auth')
 const reviewRouters = require('./routes/review')
 const addressRouters = require('./routes/address')
+const paymentRouters = require('./routes/payment')
+const searchRouters = require('./routes/search')
 
 
 app.use('/api', productRouters)
@@ -39,6 +41,8 @@ app.use('/api', ownerRouters)
 app.use('/api', userRouters)
 app.use('/api', reviewRouters)
 app.use('/api', addressRouters)
+app.use('/api', paymentRouters)
+app.use('/api', searchRouters)
 
 app.listen(3000, (err) => {
   if (err) {