keyboard_tabSkip to content
listVue Firebase Masterclass

เพิ่ม Proxy และ checkout

สารบัญ

เพิ่ม config proxy

  • โดยปกติ เราจะมีการป้องกัน CORS เอาไว้่เพื่อไม่ให้ domain ใดๆยิงเข้ามาโดยตรงได้
  • เราจะทำแบบเดียวกัน โดยเราจะให้ proxy เข้า cloud function ในฐานะ host เดียวกันเพื่อไม่ติด CORS

ที่ vite.config.js

javascript
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    proxy: {
      '/api': { // เพิ่มตรงนี้เข้ามา
        target: 'http://127.0.0.1:5010/<project_name>/us-central1/api',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      }
    }
  },
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

เมื่อ setup เรียบร้อย จากนี้เวลายิงเข้า

http://127.0.0.1:5010/<project_name>/us-central1/api/placeorder

จะมีค่าเทียบเท่ากับ path นี้ เมื่อยิงผ่าน /api ของ path vue

http://127.0.0.1:5173/api/placeorder

ลง axios และ ยิง API

  • ลง library axios สำหรับยิง API เข้า POST /api/placeorder ในฝั่ง Backend
  • ส่ง token ผ่าน header ของ axios และปั้น request body หน้าตาแบบที่ spec กำหนดเอาไว้
  • return มาเป็น success url (บทนี้เราจะแค่ console.log เอาไว้ก่อน เราจะมาเชื่อมให้ครบในบท omise)

ลง library axios โดย

bash
npm install axios

ที่ stores/user/cart.js

  • เอา localstorage ทั้งหมดออกไป (ไม่ได้ใช้แล้วสำหรับเคส checkout)
  • ประกอบ checkout object ให้ถูกต้องก่อนส่งเข้า axios ตาม spec ที่กำหนดกันไว้
  • ยิง await axios.post('/api/placeorder') ด้วย object checkout และ access token ใน header (กรณีที่ login user)
javascript
import axios from 'axios'

export const useUserCartStore = defineStore('user-cart', {
  state: () => ({
    items: [],
    checkout: {}
  }),
  getters: {
    summaryPrice (state) {
      return state.items.reduce((acc, item) => acc + (item.price * item.quantity), 0)
    },
    quantity (state) {
      return state.items.reduce((acc, item) => acc + item.quantity, 0)
    },
    user (state) {
      const accountStore = useAccountStore()
      return accountStore.user
    },
    cartRef (state) {
      return ref(realtimeDB, `carts/${this.user.uid}`)
    }
  },
  actions: {
    /* code เหมือนเดิม */
    async checkout (checkoutData) {
      try {
        let checkout = {
          ...checkoutData,
          products: this.items.map(product => ({
            productId: product.productId,
            quantity: product.quantity
          }))
        }

        const response = await axios.post('/api/placeorder', {
          source: 'test-source-id', // mock ไว้ก่อน เดี๋ยวเราจะมาปรับตอน omise
          checkout
        }, {
          headers: {
            'Authorization': this.user.accessToken // ดึง access token จาก Firebase Authentication
          }
        })
        return response.data

        // เอา localstorage ทั้งหมดออกไป
      } catch (error) {
        console.log('error', error.code)
        throw new Error('out of stock')
      }
    }
  }
})

ที่ CheckoutView

  • นำ url ที่ได้รับมา redirect ไปยังหน้า success
html
<script setup>
import UserLayout from '@/layouts/UserLayout.vue'

const checkout = async () => {
  // submit checkout data
  try {
    // เพิ่ม validate
    if (
      !userCheckoutData.email ||
      !userCheckoutData.name ||
      !userCheckoutData.address
    ) {
      throw new Error('Please add email, name, address')
    }
    // เพิ่ม ส่งข้อมูล
    const result = await userCartStore.checkout(userCheckoutData)
    // เพิ่ม redirect ไปยังหน้าที่รับมา
    location.href = result.redirectUrl
  } catch (error) {
    alert(error.message)
  }
}
</script>

เมื่อทุกอย่างถูกต้องเรียบร้อยจะต้องเกิด record ที่ Firestore ออกมา

placeorder-01