Clone the repo of this open source marketplace frontend here :
DEPLOY TO DO BUTTON
Build Setup
# 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
Create your application using this settings :
? 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
After finish run the app using yarn dev
and you should see this screen :
Now go to the nuxt.config.js
and search for this line below, and change dark
to false
:
...
vuetify: {
defaultAssets: {icons: 'fa'},
customVariables: ['~/assets/variables.scss'],
theme: {
dark: false,
themes: {
dark: {
...
We will be using non dark mode for now but it's a matter of choice if you want to make it dark
you can just put it to true
, now after you change the theme to light then change the content in layouts/default.vue
:
<template>
<v-app >
<nuxt/>
</v-app>
</template>
After you finish filling the content inside layouts/default.vue
, go to pages/index.vue
and write this code, to create our homepage :
<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>
Here you can see that index.vue
use Home
as their base component, let's now create our Home
component, create components/Home.vue
then write code like this :
<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>
And then you will got this as a homepage :
Go to nuxt.config.js
and add server
object
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: {},
}
Create a login page go to pages/login.vue
to create a login form that can login to 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>
Create the component in components/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>
Notice that we added configs.github_client_id
you can get that by creating oauth apps in github developer setting https://github.com/settings/developers
create new oauth apps then copy paste the github client id there,now let's create our environment variable create a folder called utils
and then create a file called configs.js
this will be our global configuration to get variable like github_client_id, github_client_secret etc.
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}
When in development you also need .env
file to make it easy to handle the environment variable go ahead and create .env
with this value :
github_client_id=<github_client_id>
paypal_client_id=<paypal_client_id>
url=http://localhost:4000
prefix=
Change the value according to your need,after that create a dashboard go to pages/dashboard.vue
and write this code :
<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>
Create a dashboard component to make it more easy to maintain late go ahead and create components/Dashboard.vue
and write this code :
<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>
Inside Dashboard.vue
component if you notice there is four more component inside the Dashboard.vue
component we make that so that the component is more modular and easy to maintain for later use, now let's go ahead and create the first Dashboard.vue
modular component components/dashboard_components/DashboardInfo.vue
we will use this to get an info of our paypal balance and github username :
<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>
After that go ahead and create our second modular component components/dashboard_components/DashboardForSale.vue
we will use this component to show our repo that we can sell :
<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>
After that add components/dashboard_component/DashboardOwned.vue
to see all of our that we bought from opensource marketplace
<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>
Finally add components/dashboard_components/DashboardRepoAll.vue
to show all our repo from our 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>
Now in order for us to accept the redirect url we need route to save the token that we get from github login create pages/callback.vue
in order to do that and write this code :
<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>
We also need to have a link where we can share the repo that we sell go create one at pages/detail
<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>
Now you finish creating the frontend let's go create the backend on step 2
Top comments (0)