1단계 - Nuxtjs를 사용하여 프런트엔드 만들기

149587 단어 dohackathon
이 오픈 소스 마켓플레이스 프런트엔드의 저장소를 여기에서 복제하십시오.


캣플립 / 오픈소스-마켓플레이스-프론트엔드






할일 버튼 배치



빌드 설정


# install dependencies
$ yarn install

# serve with hot reload at localhost:3000
$ yarn dev

# build for production and launch server
$ yarn build
$ yarn start

# generate static project
$ yarn generate

For detailed explanation on how things work, check out Nuxt.js docs.




First of all create a nuxtjs application by using this command :

yarn create nuxt-app opensource-marketplace-frontend


다음 설정을 사용하여 애플리케이션을 생성합니다.

? Project name: frontend
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios
? Linting tools: ESLint, Prettier
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/JAMStack hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: None


완료 후 yarn dev를 사용하여 앱을 실행하면 다음 화면이 표시됩니다.



이제 nuxt.config.js로 이동하여 아래에서 이 줄을 검색하고 darkfalse로 변경합니다.

...
vuetify: {
    defaultAssets: {icons: 'fa'},
    customVariables: ['~/assets/variables.scss'],
    theme: {
      dark: false,
      themes: {
        dark: {
...


지금은 어두운 모드가 아닌 모드를 사용하지만 원하는 경우 선택의 문제입니다dark. 이제 테마를 밝게 변경한 후 true에서 콘텐츠를 변경하면 됩니다. :

<template>
  <v-app >
<nuxt/>
  </v-app>
</template>

layouts/default.vue 안의 내용을 다 채운 후 layouts/default.vue로 이동하여 다음 코드를 작성하여 홈페이지를 만듭니다.

<template>
  <Home :login="login" />
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import Home from '@/components/Home.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
  components: {
    Home,
  },
})
export default class MyStore extends Vue {
  public login: boolean =false;

      mounted(){
        this.login=Cookies.get('token') && Cookies?.get('token')?.trim() !== ''
      ? true
      : false
      }
}
</script>



여기에서 pages/index.vueindex.vue를 기본 구성 요소로 사용하는 것을 볼 수 있습니다. 이제 Home 구성 요소를 만들고 Home를 만든 다음 다음과 같은 코드를 작성해 보겠습니다.

<template>
  <div :class="['mx-5', 'my-5']">
    <v-row justify="center">
      <div
        :class="[`text-h1`, 'text-center']"
        v-text="'Open Source Marketplace'"
      ></div>
    </v-row>
    <v-row justify="center">
      <div
        :class="[`text-h3`, 'px-5', 'text-center', 'my-5']"
        v-text="'Here you can buy or sell open source repo'"
      ></div>
    </v-row>
    <v-row justify="center" :class="['my-2']">
      <v-btn
        :class="['my-2']"
        color="info"
        elevation="2"
        v-show="login"
        href="/dashboard"
        >DASHBOARD</v-btn
      >
      <v-btn
        :class="['my-2']"
        color="info"
        elevation="2"
        href="/login"
        v-show="!login"
        >LOGIN</v-btn
      >
      <v-btn
        :class="['my-2', 'mx-2']"
        color="error"
        elevation="2"
        v-show="login"
        @click="logout"
        >LOGOUT</v-btn
      >
    </v-row>
    <v-row>
      <v-card
        class="mx-auto my-12"
        max-width="374"
        :key="index"
        v-for="(item, index) in forSale"
      >
        <v-img height="250" :src="item.openGraphImageUrl"></v-img>

        <v-card-title>{{ item.name }}</v-card-title>

        <v-card-text>
          <div>{{ item.description }}</div>
        </v-card-text>

        <v-divider class="mx-4"></v-divider>

        <v-card-actions>
          <v-flex>$ {{ item.amount }}</v-flex>
          <v-flex v-if="item.username !== username && !item.owned"
            ><div class="d-flex justify-end">
              <v-btn
              :disabled="disabled"
                class="d-flex justify-end"
                color="deep-purple lighten-2"
                @click="buyNow(item._id)"
                text
              >
                Buy Now
              </v-btn>
            </div></v-flex
          >
          <v-flex v-if="item.username === username || item.owned"
            ><div class="d-flex justify-end">

              <v-btn
              :disabled="disabled"
                class="d-flex justify-end"
                color="deep-purple lighten-2"
                :href="item.url"
                target="_blank"
                text
              >
                GO TO URL
              </v-btn>
            </div></v-flex
          >
        </v-card-actions>
      </v-card>
    </v-row>
  </div>
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue, Prop } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
  @Prop({ required: true }) readonly login!: boolean
  public forSale: Array<object> = []
  public username: string = ''
  public disabled: boolean = false
  public buy_paypal_url: string = ""
  logout() {
    Cookies.remove('token')
    window.location.reload()
  }
  async mounted() {
console.log(configs)
    const token = Cookies.get('token')
    const ownedRepoUrl = configs.get_owned_repo_url
    const url = configs.for_sale_repo_url
    try {
      const { data } = await this.$axios.get(`${url}?token=${token}`)
      const ownedRepo = await this.$axios.get(`${ownedRepoUrl}?token=${token}`)

      this.forSale = data.data.data.map((a:any) => {
        if (
          ownedRepo.data.data.filter((b:any) => b.owner_username === a.username&&a.name===b.name)
            .length > 0
        ) {
          a.owned = true
          return a
        } else {
          return a
        }
      })
      this.username = data.data.username
    } catch (e) {
      console.log(e.message)
    }
  }
  async buyNow(_id:any) {
    this.disabled=true;
    const token = Cookies.get('token')
    const url=<string>configs.buy_paypal_url;
    const res = await this.$axios.post(url, { _id, token })
    if (res.data) {
      const link=res.data.result.links.filter((a:any)=>a.rel==="approve")[0].href
      window.location.href=link;
    }else{
      this.disabled=false;
      alert("error")
    }
  }
}
</script>


그러면 다음과 같은 홈페이지가 표시됩니다.


components/Home.vue로 이동하여 nuxt.config.js 개체를 추가합니다.

import colors from 'vuetify/es5/util/colors'

export default {
  // Target (https://go.nuxtjs.dev/config-target)
  server: {
    port: 8080, // default: 3000
    host: '0.0.0.0' // default: localhost
  },
  target: 'server',
  env: {
    github_client_id: process.env.github_client_id,
    paypal_client_id:process.env.paypal_client_id,
    url:process.env.url,
    prefix:process.env.prefix,
  },
  // Global page headers (https://go.nuxtjs.dev/config-head)
  head: {
    titleTemplate: '%s ',
    title: 'Open Source Marketplace',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
  },

  // Global CSS (https://go.nuxtjs.dev/config-css)
  css: [],

  // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
  plugins: [],

  // Auto import components (https://go.nuxtjs.dev/config-components)
  components: true,

  // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
  buildModules: [
    // https://go.nuxtjs.dev/typescript
    '@nuxt/typescript-build',
    // https://go.nuxtjs.dev/vuetify
    '@nuxtjs/vuetify',
    '@nuxtjs/dotenv'
  ],

  // Modules (https://go.nuxtjs.dev/config-modules)
  modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
  ],

  // Axios module configuration (https://go.nuxtjs.dev/config-axios)
  axios: {},

  // Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify)
  vuetify: {
    defaultAssets: {icons: 'fa'},
    customVariables: ['~/assets/variables.scss'],
    theme: {
      dark: false,
      themes: {
        dark: {
          primary: colors.blue.darken2,
          accent: colors.grey.darken3,
          secondary: colors.amber.darken3,
          info: colors.teal.lighten1,
          warning: colors.amber.base,
          error: colors.deepOrange.accent4,
          success: colors.green.accent3,
        },
      },
    },
  },

  // Build Configuration (https://go.nuxtjs.dev/config-build)
  build: {},
}


로그인 페이지 만들기 server로 이동하여 github에 로그인할 수 있는 로그인 양식을 만듭니다.

<template>
  <Login />
</template>
<script lang="ts">
import Login from '@/components/Login.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
  components: {
    Login,
  },
})
export default class MyStore extends Vue {}
</script>

pages/login.vue에서 구성 요소를 생성합니다.

<template>

   <v-row justify="center" align="center">
<v-card>
  <v-card-text>
    <v-row :class="['my-3','mx-3','text-h4']">LOGIN USING YOUR GITHUB ACCOUNT</v-row>
    <v-row align="center" justify="center">
      <v-btn @click="login_github"><v-icon class="mx-2 my-2">fab fa-github</v-icon>LOGIN</v-btn>
    </v-row>
  </v-card-text>
</v-card>
   </v-row>

</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
  login_github(){
    window.location.href="https://github.com/login/oauth/authorize?scope=repo&client_id="+configs.github_client_id
  }
}
</script>



추가한components/Login.vue github 개발자 설정configs.github_client_id에서 oauth 앱을 생성하여 얻을 수 있습니다. 새 oauth 앱을 만든 다음 거기에 github 클라이언트 ID를 복사하여 붙여넣습니다. 이제 환경 변수를 만들고 https://github.com/settings/developers라는 폴더를 만든 다음 utils라는 파일을 생성합니다. 이것은 github_client_id, github_client_secret 등과 같은 변수를 가져오는 전역 구성이 됩니다.

const configs={}
configs.url=process.env.url;
configs.prefix=process.env.prefix;
configs.github_client_id=process.env.github_client_id
configs.paypal_client_id=process.env.paypal_client_id
configs.save_paypal_url=`${configs.url}${configs.prefix}/save-paypal`
configs.buy_paypal_url=`${configs.url}${configs.prefix}/buy-paypal`
configs.for_sale_repo_url=`${configs.url}${configs.prefix}/for-sale-repo`
configs.disconnect_paypal_url=`${configs.url}${configs.prefix}/disconnect-paypal`
configs.redirect_uri_paypal=`${configs.url}${configs.prefix}/paypal-auth`
configs.unlist_repo_url=`${configs.url}${configs.prefix}/unlist-repo`
configs.sell_repo_url=`${configs.url}${configs.prefix}/sell-repo`
configs.get_all_repo_url=`${configs.url}${configs.prefix}/get-all-repo`
configs.get_profile_url=`${configs.url}${configs.prefix}/get-profile`
configs.get_for_sale_url=`${configs.url}${configs.prefix}/get-for-sale-repo`
configs.get_owned_repo_url=`${configs.url}${configs.prefix}/get-owned-repo`
configs.get_paypal_url=`${configs.url}${configs.prefix}/get-paypal`
configs.list_repo_url=`${configs.url}${configs.prefix}/list-repo`
configs.repo_detail_url=`${configs.url}${configs.prefix}/repo-detail`
module.exports={configs}


개발 중에 환경 변수를 쉽게 처리할 수 있도록 configs.js 파일도 필요합니다. 계속해서 다음 값으로 .env를 생성하십시오.

github_client_id=<github_client_id>
paypal_client_id=<paypal_client_id>
url=http://localhost:4000
prefix=



필요에 따라 값을 변경한 후 대시보드를 만든 후 .env로 이동하여 다음 코드를 작성합니다.

<template>
  <Dashboard :login="login" />
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import Dashboard from '@/components/Dashboard.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
  components: {
    Dashboard,
  },
})
export default class MyStore extends Vue {
  public login: boolean =false;

      mounted(){
this.login=Cookies.get('token') && Cookies?.get('token')?.trim() !== ''
      ? true
      : false
      }
}
</script>



나중에 유지 관리하기가 더 쉽도록 대시보드 구성 요소를 생성하고 다음 코드를 생성pages/dashboard.vue하고 작성합니다.

<template>
  <v-container>
    <v-row justify="space-between">
      <v-col cols="4" class="text-h4 font-weight-bold"
        ><a href="/" style="text-decoration: none; color: black">Home</a></v-col
      >
      <v-col cols="4" class="d-flex justify-end"
        ><v-btn @click="logout">LOGOUT</v-btn></v-col
      >
    </v-row>
    <DashboardInfo
      :disabled="disabled"
      :username="username"
      :profilePhoto="profilePhoto"
      :paypalToken="paypalToken"
      :paypalBalance="paypalBalance"
      @disconnect="disconnectPaypal"
      @connect="connectPaypal"
    />
    <v-row justify="space-between">
      <v-col cols="4" class="text-h4 font-weight-bold"
        >For Sale Repo List</v-col
      >
    </v-row>
    <DashboardForSale
      :disabled="disabled"
      :ownedRepo="false"
      :amountRefresh="amountRefresh"
      @get-all-repo="getAllRepo"
      :listRepo="forSale"
      :paypalToken="paypalToken"
      @sell-repo="sellRepo($event.name, $event.amount)"
      @unlist-repo="unlistRepo($event.repo_id)"
    />
    <v-row justify="space-between">
      <v-col cols="4" class="text-h4 font-weight-bold">Owned Repo</v-col>
    </v-row>
    <DashboardOwned
      :amountRefresh="amountRefresh"
      :disabled="disabled"
      :ownedRepo="true"
      :paypalToken="paypalToken"
      :listRepo="ownedRepo"
    />
    <DashboardRepoAll
      :disabled="disabled"
      @list-repo="listRepo($event.item)"
      @get-all-repo="getAllRepo($event.after_, $event.before_)"
      :pageInfo_="pageInfo_"
      :dialog="dialog"
      :allRepo="allRepo"
    />
    <v-snackbar v-model="snackbarAmount">
      the amount shouldn't be negative or zero
    </v-snackbar>
  </v-container>
</template>

<script lang="ts">
import Cookies from 'js-cookie'
import DashboardInfo from '@/components/dashboard_components/DashboardInfo.vue'
import DashboardForSale from '@/components/dashboard_components/DashboardForSale.vue'
import DashboardOwned from '@/components/dashboard_components/DashboardOwned.vue'
import DashboardRepoAll from '@/components/dashboard_components/DashboardRepoAll.vue'
import { Component, Vue, Prop } from 'nuxt-property-decorator'
import { configs } from '@/utils/configs.js'
@Component({
  components: {
    DashboardInfo,
    DashboardForSale,
    DashboardOwned,
    DashboardRepoAll,
  },
})
export default class MyStore extends Vue {
  @Prop({ required: true }) readonly login!: boolean
  public dialog: boolean = false
  public username: string = ''
  public profilePhoto: string = ''
  public snackbarAmount: boolean = false
  public paypalToken: boolean = false
  public forSale: Array<object> = []
  public allRepo: Array<object> = []
  public ownedRepo: Array<object> = []
  public paypalBalance: number = 0
  public amountRefresh: number = 0
  public disabled: boolean = false
  public pageInfo_: object = {hasPreviousPage:false,hasNextPage:false,startCursor:"",endCursor:""}
  logout() {
    Cookies.remove('token')
    window.location.href = '/'
  }
  async created() {
    // if (!this.login) window.location.href = '/'
    this.disabled = true
    const token = Cookies.get('token')
    const url = configs.get_profile_url
    const forSaleUrl = configs.get_for_sale_url
    const ownedRepoUrl = configs.get_owned_repo_url
    const getPaypalUrl = configs.get_paypal_url
    const profile = await this.$axios.get(`${url}?token=${token}`)
    this.username = profile.data.data.login
    this.profilePhoto = profile.data.data.avatarUrl
    const forSale = await this.$axios.get(`${forSaleUrl}?token=${token}`)
    this.forSale = forSale.data.data
    const ownedRepo = await this.$axios.get(`${ownedRepoUrl}?token=${token}`)
    this.ownedRepo = ownedRepo.data.data
    const paypalToken = await this.$axios.get(`${getPaypalUrl}?token=${token}`)

    if (paypalToken.data.status && !paypalToken.data.data.disconnect) {
      this.paypalToken = true
      this.paypalBalance = paypalToken.data.data.amount
    }
    this.disabled = false
  }
  async getAllRepo(after_: string, before_: string): Promise<void> {
     this.disabled = true
    const token = Cookies.get('token')
    const url = configs.get_all_repo_url

    if (this.allRepo.length === 0) {
      const { data } = await this.$axios.get(`${url}?token=${token}`)
      this.allRepo = data.data.nodes.map(({...other})=>(this.forSale.filter(({repo_id}:any)=>repo_id===other.id).length>0?{added:true,...other}:{...other}))
      console.log(this.allRepo)
      this.pageInfo_ = data.data.pageInfo
    } else if(typeof after_==="string"||typeof before_==="string"){
      const { data } = await this.$axios.get(
        `${url}?token=${token}${before_ ? `&before=${before_}` : ''}${
          after_ ? `&after=${after_}` : ''
        }`
      )
      this.allRepo = data.data.nodes.map(({...other})=>(this.forSale.filter(({repo_id}:any)=>repo_id===other.id).length>0?{added:true,...other}:{...other}))
      this.pageInfo_ = data.data.pageInfo
    }

    this.dialog = true
    this.disabled = false
  }
  async sellRepo(name: string, amount: number) {
    // console.log(amount)
    this.disabled = true
    if (Number(amount) === 0 || Number(amount) < 0 || !amount) {

      this.snackbarAmount = true
      this.disabled = false
      return
    } else {
      const token = Cookies.get('token')
      const url = configs.sell_repo_url

      const { data } = await this.$axios.post(`${url}?token=${token}`, {
        name,
        amount,
      })
      this.amountRefresh = 0
      this.forSale = data.data
    }
    this.disabled = false
  }
  async listRepo(item: object): Promise<void> {
      this.disabled = true
    const token = Cookies.get('token')
    const url = configs.list_repo_url
    const { data } = await this.$axios.post(`${url}?token=${token}`, { item })
    this.forSale = data.data
    this.dialog=false
    this.disabled = false
  }
  async unlistRepo(id: string) {
    this.disabled = true
    const token = Cookies.get('token')
    const url = configs.unlist_repo_url
    const { data } = await this.$axios.post(`${url}?token=${token}`, { id })
    this.forSale = data.data
    this.disabled = false
  }
  async connectPaypal() {
    if (this.username.trim() !== '') {
      window.location.href = `https://www.sandbox.paypal.com/connect/?flowEntry=static&client_id=${configs.paypal_client_id}&response_type=code&scope=email&redirect_uri=${configs.redirect_uri_paypal}`
    } else {
      alert('please wait until username shown')
    }
  }
  async disconnectPaypal() {
    this.disabled = true
    if (this.username.trim() !== '') {
      const url = configs.disconnect_paypal_url
      const token = Cookies.get('token')
     await this.$axios.post(`${url}?token=${token}`)
      this.paypalToken = false
    } else {
      alert('please wait until username shown')
    }
    this.disabled = false
    if (this.forSale.length > 0) {
      this.getforSale()
    }
  }
  async getforSale() {
    this.disabled = true
    const token = Cookies.get('token')
    const url = configs.get_for_sale_url
    const { data } = await this.$axios.get(`${url}?token=${token}`)
    this.forSale = data.data
    this.disabled = false
  }
}
</script>


components/Dashboard.vue 구성 요소 내부 Dashboard.vue 구성 요소 내부에 4개의 구성 요소가 더 있음을 알게 되면 나중에 사용할 수 있도록 구성 요소를 더 모듈화하고 유지 관리하기 쉽게 만듭니다. 이제 첫 번째Dashboard.vue 모듈 구성 요소를 생성하겠습니다. Dashboard.vue 이것을 사용하여 페이팔 잔액 및 github 사용자 이름 정보를 얻습니다.

<template>
  <v-row>
    <v-card max-width="344" outlined>
      <v-list-item three-line>
        <v-list-item-content>
          <v-list-item-title class="headline mb-1">
            Github Username
          </v-list-item-title>
          <v-list-item-title class="text-h5">{{username}}</v-list-item-title>
        </v-list-item-content>

        <v-list-item-avatar size="80" color="grey">
          <v-img :src="profilePhoto" />
        </v-list-item-avatar>
      </v-list-item>
    </v-card>
    <v-card class="mx-5" max-width="344" outlined>
      <v-list-item three-line>
        <v-list-item-content>
          <v-list-item-title class="headline mb-1"> Balance </v-list-item-title>
          <v-list-item-title>
            <v-row justify="space-between">

              <v-col class="font-weight-bold text-h5" v-if="paypalToken">$ {{paypalBalance}}</v-col>

              <v-col v-if="paypalToken"><v-btn color="red" :disabled="disabled" @click="disconnect">DISCONNECT PAYPAL</v-btn></v-col>
              <v-col v-if="!paypalToken"><v-btn color="blue" :disabled="disabled" @click="connect">CONNECT PAYPAL</v-btn></v-col>
            </v-row>
          </v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </v-card>
  </v-row>
</template>
<script lang="ts">
import { Component, Vue, Prop,Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
  @Prop({ required: true }) readonly username!: string
  @Prop({ required: true }) readonly profilePhoto!: string
    @Prop({ required: false }) readonly paypalBalance!: number
    @Prop({ required: true }) readonly paypalToken!: boolean
    @Prop({ required: true }) readonly disabled!: boolean

@Emit()
connect(){}
@Emit()
disconnect(){}
}
</script>



그런 다음 계속해서 두 번째 모듈 구성 요소components/dashboard_components/DashboardInfo.vue를 생성합니다. 이 구성 요소를 사용하여 판매할 수 있는 저장소를 표시합니다.

<template>
  <div>
    <v-row class="mb-2" ><v-btn @click="getAllRepo" :disabled="disabled">SELL REPO</v-btn></v-row
    >
    <v-row>
      <v-card
        width="400"
        class="mx-2 my-2"
        :key="index"
        v-for="(item, index) in listRepo"
      >
        <v-card-title>
          <v-list-item class="grow">
            <v-list-item-content>
              <v-list-item-title>{{ item.name }}</v-list-item-title>
            </v-list-item-content>

            <v-row align="center" justify="end"> {{item.isPrivate?"Private":"Public"}} </v-row>
          </v-list-item>
        </v-card-title>

        <v-card-text class="text-md font-weight-bold">
          <v-list-item>
            <v-list-item-content>{{ item.description }}</v-list-item-content>
            <v-list-item-avatar tile size="100" color="grey">
              <v-img :src="item.openGraphImageUrl" />
            </v-list-item-avatar>
          </v-list-item>
        </v-card-text>
        <v-card-action
          ><v-row class="d-flex align-content-center mx-5">
            <v-col cols="5" class="d-flex justify-start align-content-center">
              <div
                class="d-flex align-center text-h5"
                :style="{ height: '100%' }"
                v-if="item.sell === 'SELL'&&!ownedRepo"
              >
                $ {{ item.amount }}
              </div>
              <v-text-field
                v-if="item.sell === 'UNLIST'"
                label="Amount"
                type="number"
                outlined
                prefix="$"
                :disabled="!paypalToken"
                v-model="item.amount"
              ></v-text-field>
            </v-col>
            <v-col class="d-flex mt-2 justify-end">
              <v-btn
                @click="sellRepo(item.name, item.amount)"
                color="red"
                v-if="item.sell === 'UNLIST'&&!ownedRepo"
                :disabled="!paypalToken||disabled"
                >SELL</v-btn
              ><v-btn :disabled="!paypalToken||disabled" v-if="item.sell === 'SELL'&&!ownedRepo" @click="unlistRepo(item.repo_id)"
                >UNLIST</v-btn
              >
              <v-btn v-if="ownedRepo" target="_blank" :href="item.url"
                >GO TO URL</v-btn
              >
            </v-col>
          </v-row></v-card-action
        >
      </v-card>
    </v-row>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
  @Prop({ required: false }) readonly refreshRepo!: void
  @Prop({ required: false }) readonly paypalToken!: boolean
  @Prop({ required: true }) readonly listRepo!: Array<object>
  @Prop({ required: true }) readonly amountRefresh!: number
  @Prop({ required: true }) readonly ownedRepo!: boolean
    @Prop({ required: true }) readonly disabled!: boolean

  public amount: number=this.amountRefresh
  @Emit()
  getAllRepo() {

  }
  @Emit()
  sellRepo(name: string, amount: number) {
    return { name, amount }
  }
  @Emit()
  unlistRepo(repo_id: string) {
    return { repo_id }
  }
}
</script>



그런 다음 components/dashboard_components/DashboardForSale.vue를 추가하여 오픈 소스 마켓플레이스에서 구매한 모든 항목을 확인합니다.

<template>
  <div>
    <v-row class="mb-2" v-if="refreshRepo"
      ><v-btn @click="getAllRepo" :disabled="disabled">SELL REPO</v-btn></v-row
    >
    <v-row>
      <v-card
        width="400"
        class="mx-2 my-2"
        :key="index"
        v-for="(item, index) in listRepo"
      >
        <v-card-title>
          <v-list-item class="grow">
            <v-list-item-content>
              <v-list-item-title>{{ item.name }}</v-list-item-title>
            </v-list-item-content>

            <v-row align="center" justify="end"> {{item.isPrivate?"Private":"Public"}}</v-row>
          </v-list-item>
        </v-card-title>

        <v-card-text class="text-md font-weight-bold">
          <v-list-item>
            <v-list-item-content>{{ item.description }}</v-list-item-content>
            <v-list-item-avatar tile size="100" color="grey">
              <v-img :src="item.openGraphImageUrl" />
            </v-list-item-avatar>
          </v-list-item>
        </v-card-text>
        <v-card-action
          ><v-row class="d-flex align-content-center mx-5">
            <v-col cols="5" class="d-flex justify-start align-content-center">
              <div
                class="d-flex align-center text-h5"
                :style="{ height: '100%' }"
                v-if="item.sell === 'SELL'&&!ownedRepo"
              >
                $ {{ item.amount }}
              </div>
              <v-text-field
                v-if="item.sell === 'UNLIST'"
                label="Amount"
                type="number"
                outlined
                prefix="$"
                :disabled="!paypalToken"
                v-model="amount"
              ></v-text-field>
            </v-col>
            <v-col class="d-flex mt-2 justify-end">
              <v-btn
                @click="sellRepo(item._id, amount)"
                color="red"
                v-if="item.sell === 'UNLIST'&&!ownedRepo"
                :disabled="!paypalToken||disabled"
                >SELL</v-btn
              ><v-btn :disabled="!paypalToken||disabled" v-if="item.sell === 'SELL'&&!ownedRepo" @click="unlistRepo(item._id)"
                >UNLIST</v-btn
              >
              <v-btn v-if="ownedRepo" target="_blank" :href="item.url"
                >GO TO URL</v-btn
              >
            </v-col>
          </v-row></v-card-action
        >
      </v-card>
    </v-row>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
  @Prop({ required: false }) readonly refreshRepo!: void
  @Prop({ required: false }) readonly paypalToken!: boolean
  @Prop({ required: true }) readonly listRepo!: Array<object>
  @Prop({ required: true }) readonly amountRefresh!: number
  @Prop({ required: true }) readonly ownedRepo!: boolean
    @Prop({ required: true }) readonly disabled!: boolean

  public amount: number=this.amountRefresh
  @Emit()
  getAllRepo() {

  }
  @Emit()
  sellRepo(_id: string, amount: number) {
    return { _id, amount }
  }
  @Emit()
  unlistRepo(_id: string) {
    return { _id }
  }
}
</script>



마지막으로 components/dashboard_component/DashboardOwned.vue를 추가하여 github의 모든 저장소를 표시합니다.

<template>
<v-row justify="center">
      <v-dialog
        v-model="dialog"
                max-width="600px"
      >
      <v-card>
          <v-card-title>
            <span class="headline">Choose Your Repo To Sell</span>
          </v-card-title>
          <v-card-text>
          <v-card
    class="mx-auto"
    max-width="344"
    outlined
    :key="index"
v-for="(item, index) in allRepo"
  >
    <v-list-item three-line>
      <v-list-item-content>
        <div class="overline mb-4">
          {{item.isPrivate?"PRIVATE":"PUBLIC"}}
        </div>
        <v-list-item-title class="headline mb-1">
          {{item.name}}
        </v-list-item-title>
        <v-list-item-subtitle>{{item.description}}</v-list-item-subtitle>
      </v-list-item-content>

      <v-list-item-avatar
        tile
        size="80"
        color="grey"
      ><v-img :src="item.openGraphImageUrl"/></v-list-item-avatar>
    </v-list-item>

    <v-card-actions>
      <v-btn
        v-if="!item.added"
        rounded

        color="blue"
        :disabled="disabled"
        @click="listRepo(item)"
      >
        LIST REPO
      </v-btn>

    </v-card-actions>
  </v-card>
            <v-row justify="center" class="mt-2">
               <v-btn
      class="mx-2"
      fab
      dark
      large
      color="cyan"
      :disabled="!pageInfo_.hasPreviousPage||disabled"
      @click="getAllRepo(undefined,pageInfo_.startCursor)"
    >
      <v-icon>
        fas fa-arrow-left
      </v-icon>
    </v-btn>
                <v-btn
      class="mx-2"
      fab
      dark
      large
      color="cyan"
      :disabled="!pageInfo_.hasNextPage||disabled"
      @click="getAllRepo(pageInfo_.endCursor,undefined)"
    >
      <v-icon>
        fas fa-arrow-right
      </v-icon>
    </v-btn>
            </v-row>

          </v-card-text>

        </v-card>
      </v-dialog>
    </v-row>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
  @Prop({ required: true }) readonly dialog!: boolean
  @Prop({ required: true }) readonly allRepo!: Array<object>
  @Prop({ required: true }) readonly pageInfo_!: object
  @Prop({ required: true }) readonly disabled!: boolean
@Emit()
  getAllRepo(after_: string,before_:string) {
    return { after_,before_ }
  }
  @Emit()
  listRepo(item:object) {
    return { item}
  }

}
</script>



이제 리디렉션 URL을 수락하려면 github login createcomponents/dashboard_components/DashboardRepoAll.vue에서 얻은 토큰을 저장하고 다음 코드를 작성하기 위한 경로가 필요합니다.

<template>
  <v-row justify="center" align="center" :class="['text-h1']"
    >REDIRECTING...</v-row
  >
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue } from 'nuxt-property-decorator'
import axios from 'axios'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
  async mounted() {
    if (this.$route.query.token) {
      Cookies.set('token', this.$route.query.token)
      if(Cookies.get('redirect')){
        const redirect=Cookies.get('redirect');
        window.location.href=`${redirect}`;
        return
      }
      window.location.href = '/'
    } else {
      const token = Cookies.get('token')
      const { data } = await axios.post(`${configs.save_paypal_url}`, {
        token,
        email: this.$route.query.email,
      })
      if (data.status) {
        window.location.href = '/dashboard'
      } else {
        window.location.href = '/dashboard?error=save_paypal'
      }
    }
  }
}
</script>



또한 판매하는 저장소를 공유할 수 있는 링크가 있어야 합니다pages/callback.vue.

<template>
  <v-row justify="center" align="center" :class="['text-h1']"
    >
  <v-card

    class="mx-auto my-12"
    max-width="1000"
  >
    <template slot="progress">
      <v-progress-linear
        color="deep-purple"
        height="10"
        indeterminate
      ></v-progress-linear>
    </template>

    <v-img
      height="250"
      :src="item.openGraphImageUrl"
    ></v-img>

    <v-card-title>{{item.name}}</v-card-title>

    <v-card-text>



      <div>{{item.description}}</div>
    </v-card-text>

    <v-divider class="mx-4"></v-divider>

    <v-card-title>$ {{item.amount}}</v-card-title>



    <v-card-actions>
      <v-btn
         v-if="item.username !== username_"
        color="deep-purple lighten-2"
        text
        :disabled="disabled"
        @click="buyNow(item.repo_id,item.username,item.name)"
      >
        BUY NOW
      </v-btn>

        <v-btn
        v-if="item.username === username_"
              :disabled="disabled"
                class="d-flex justify-end"
                color="deep-purple lighten-2"
                :href="item.url"
                target="_blank"
                text
              >
                GO TO URL
              </v-btn>
    </v-card-actions>
  </v-card>
</v-row>
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
import axios from 'axios'
@Component
export default class MyStore extends Vue {
public disabled:boolean=false
public username_:string=""
public item:object={}
async mounted(){
  Cookies.remove("redirect")
  const username = this.$route.query.username
      const name = this.$route.query.name
      const url=configs.repo_detail_url
      const {data}=await axios.post(`${url}`,{username,name})
this.item=data


  if(Cookies.get("token")){
        const token=Cookies.get("token")
        const _url = configs.get_profile_url
        const profile = await this.$axios.get(`${_url}?token=${token}`)
        this.username_ = profile.data.data.login
      }
}

async buyNow(id:any,username:string,name:string) {

    this.disabled=true;
    const token = Cookies.get('token')
    if(!token){
      window.location.href="/login"
       Cookies.set('redirect', `/${username}/${name}`)
      return
    }
    Cookies.remove("redirect")
    const url=<string>configs.buy_paypal_url;
    const res = await this.$axios.post(url, { id, token })
    if (res.data) {
      const link=res.data.result.links.filter((a:any)=>a.rel==="approve")[0].href
      window.location.href=link;
    }else{
      this.disabled=false;
      alert("error")
    }
  }
}
</script>



이제 프론트엔드 생성을 마쳤습니다. 2단계에서 백엔드를 생성해 보겠습니다.

좋은 웹페이지 즐겨찾기