Browse Source

do most of the app

main
Ayush Mukherjee 2 years ago
parent
commit
2cfc4d3834
  1. 1239
      package-lock.json
  2. 2
      package.json
  3. BIN
      public/favicon.ico
  4. 3
      public/index.html
  5. 18
      src/App.vue
  6. 85
      src/components/Events.vue
  7. 58
      src/components/HelloWorld.vue
  8. 156
      src/components/Matches.vue
  9. 130
      src/components/Rosters.vue
  10. 29
      src/router/index.js
  11. 44
      src/store.js
  12. 82
      src/utils/websocket.js
  13. 5
      src/views/About.vue
  14. 60
      src/views/Home.vue
  15. 44
      src/views/Login.vue

1239
package-lock.json generated

File diff suppressed because it is too large Load Diff

2
package.json

@ -13,7 +13,9 @@
"main": "background.js",
"dependencies": {
"@tailwindcss/postcss7-compat": "^2.0.2",
"@vue/devtools": "^6.0.0-beta.6",
"autoprefixer": "^9",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"postcss": "^7",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",

BIN
public/favicon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

3
public/index.html

@ -4,8 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<title>APL Slapdash</title>
</head>
<body>
<noscript>

18
src/App.vue

@ -1,10 +1,14 @@
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
<router-view></router-view>
</template>
<style lang="scss">
</style>
<script>
import { provide } from 'vue'
import store from './store'
export default {
setup() {
provide('store', store)
},
}
</script>

85
src/components/Events.vue

@ -0,0 +1,85 @@
<template>
<h1 class="text-2xl font-bold uppercase mb-10">events management</h1>
<div class="grid grid-cols-2 gap-x-8">
<table class="table-auto">
<thead>
<tr>
<th class="border border-gray-400 text-left px-8 py-4">ID</th>
<th class="border border-gray-400 text-left px-8 py-4">Name</th>
</tr>
</thead>
<tbody>
<tr class="item" :class="item === e._id ? 'active' : ''" @click="setItem(e)" v-for="e in store.state.events" :key="e._id">
<td class="border border-gray-400 text-left px-8 py-4">{{ e._id }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.name }}</td>
</tr>
</tbody>
</table>
<div>
<h2 class="text-lg font-bold">Create / Update</h2>
<form name="form" @submit.prevent="form">
<p class="mt-4">Event name</p>
<input v-model="name" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
<button class="block w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Submit</button>
<button @click.prevent="delForm" v-if="item" class="block mt-4 w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Delete</button>
</form>
</div>
</div>
</template>
<script>
import { inject, ref } from 'vue'
import { create, update, del } from '../utils/websocket'
export default {
setup() {
const store = inject('store')
const item = ref('')
const name = ref('')
const setItem = (e) => {
item.value = e._id
name.value = e.name
}
const form = () => {
if (item.value !== '') {
update('events', item.value, {
name: name.value,
})
} else if (name.value !== '') {
create('events', {
name: name.value,
})
}
}
const delForm = () => {
if (item.value) {
del('events', item.value)
item.value = ''
name.value = ''
}
}
return {
store,
item,
name,
setItem,
form,
delForm,
}
},
}
</script>
<style>
.item:hover {
@apply bg-gray-300 cursor-pointer;
}
.item.active {
@apply bg-gray-400;
}
</style>

58
src/components/HelloWorld.vue

@ -1,58 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

156
src/components/Matches.vue

@ -0,0 +1,156 @@
<template>
<h1 class="text-2xl font-bold uppercase mb-10">match management</h1>
<div class="grid grid-cols-2 gap-x-8">
<div class="overflow-x-auto">
<table class="table-auto">
<thead>
<tr>
<th class="border border-gray-400 text-left px-8 py-4">Type</th>
<th class="border border-gray-400 text-left px-8 py-4">Blue</th>
<th class="border border-gray-400 text-left px-8 py-4">Orange</th>
<th class="border border-gray-400 text-left px-8 py-4">Started</th>
<th class="border border-gray-400 text-left px-8 py-4">Done</th>
<th class="border border-gray-400 text-left px-8 py-4">Best Of</th>
<th class="border border-gray-400 text-left px-8 py-4">Series score</th>
<th class="border border-gray-400 text-left px-8 py-4">Game scores</th>
</tr>
</thead>
<tbody>
<tr class="item" :class="item === e._id ? 'active' : ''" @click="setItem(e)" v-for="e in store.state.matches" :key="e._id">
<td class="border border-gray-400 text-left px-8 py-4">{{ e.type }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.blue.name }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.orange.name }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.started }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.done }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.bestOf }}</td>
<td class="border border-gray-400 text-left px-8 py-4">{{ e.series.blue }} - {{ e.series.orange }}</td>
<td class="border border-gray-400 text-left px-8 py-4">
<table v-if="e.games">
<tbody>
<tr v-for="(g, idx) in e.games" :key="g._id">
<td>Game {{ idx }}: {{ g.blue }} - {{ g.orange }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<h2 class="text-lg font-bold">Create / Update</h2>
<form name="form" @submit.prevent="form">
<p class="mt-4">Match type</p>
<input v-model="type" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
<p class="mt-4">Blue team</p>
<select v-model="blue" class="block my-4 border border-gray-500 rounded-lg bg-white w-64 h-8 px-4">
<option v-for="r in store.state.rosters" :key="r._id" :value="r._id">{{ r.name }}</option>
</select>
<p class="mt-4">Orange team</p>
<select v-model="orange" class="block my-4 border border-gray-500 rounded-lg bg-white w-64 h-8 px-4">
<option v-for="r in store.state.rosters" :key="r._id" :value="r._id">{{ r.name }}</option>
</select>
<p class="mt-4">Started</p>
<input :checked="started" class="my-4 border border-gray-500 rounded-lg w-6 h-6" type="checkbox" required />
<p class="mt-4">Done</p>
<input :checked="done" class="my-4 border border-gray-500 rounded-lg w-6 h-6" type="checkbox" required />
<p class="mt-4">Best Of</p>
<input v-model="bestof" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="number" required />
<p v-if="item" class="mt-4">Series Score</p>
<input v-if="item" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="number" required />
<p v-if="item" class="mt-4">Game Scores</p>
<button class="block w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Submit</button>
<button @click.prevent="delForm" v-if="item" class="block mt-4 w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Delete</button>
</form>
</div>
</div>
</template>
<script>
import { inject, ref } from 'vue'
import { create, update, del } from '../utils/websocket'
export default {
setup() {
const store = inject('store')
const item = ref('')
const type = ref('')
const blue = ref('')
const orange = ref('')
const started = ref(false)
const done = ref(false)
const bestof = ref(0)
const setItem = (e) => {
item.value = e._id
// name.value = e.name
// logo.value = e.logo
// players.value = e.players
}
const addPlayer = () => {
players.value.push({
name: '',
account: '',
})
}
const reset = () => {
item.value = ''
name.value = ''
logo.value = ''
players.value = []
}
const form = () => {
if (item.value !== '') {
update('rosters', item.value, {
name: name.value,
logo: logo.value,
players: players.value,
})
} else if (name.value !== '') {
create('rosters', {
name: name.value,
logo: logo.value,
players: players.value,
})
}
reset()
}
const delForm = () => {
if (item.value) {
del('rosters', item.value)
reset()
}
}
return {
store,
item,
type,
blue,
orange,
started,
done,
bestof,
setItem,
form,
delForm,
addPlayer,
}
},
}
</script>
<style>
.item:hover {
@apply bg-gray-300 cursor-pointer;
}
.item.active {
@apply bg-gray-400;
}
</style>

130
src/components/Rosters.vue

@ -0,0 +1,130 @@
<template>
<h1 class="text-2xl font-bold uppercase mb-10">rosters management</h1>
<div class="grid grid-cols-2 gap-x-8">
<table class="table-auto">
<thead>
<tr>
<th class="border border-gray-400 text-left px-8 py-4">Name</th>
<th class="border border-gray-400 text-left px-8 py-4">Logo</th>
<th class="border border-gray-400 text-left px-8 py-4">Players</th>
</tr>
</thead>
<tbody>
<tr class="item" :class="item === e._id ? 'active' : ''" @click="setItem(e)" v-for="e in store.state.rosters" :key="e._id">
<td class="border border-gray-400 text-left px-8 py-4">{{ e.name }}</td>
<td class="border border-gray-400 text-left px-8 py-4"><img class="w-12 h-12" :src="e.logo" :alt="e.name"></td>
<td class="border border-gray-400 text-left px-8 py-4">
<table v-if="e.players">
<tbody>
<tr v-for="p in e.players" :key="p._id">
<td>{{ p.name }}: {{ p.account }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<div>
<h2 class="text-lg font-bold">Create / Update</h2>
<form name="form" @submit.prevent="form">
<p class="mt-4">Roster name</p>
<input v-model="name" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
<p class="mt-4">Roster logo</p>
<input v-model="logo" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
<fieldset v-for="(n, i) in players.length" :key="i" class="border border-gray-400 rounded px-6 my-4">
<legend>Player Info</legend>
<p class="mt-4">Player name</p>
<input v-model="players[n - 1].name" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
<p class="mt-4">Player account name</p>
<input v-model="players[n - 1].account" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="text" required />
</fieldset>
<button @click.prevent="addPlayer()" class="block w-64 h-10 my-4 text-white bg-red-700 rounded-lg hover:bg-red-600">Add player</button>
<button class="block w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Submit</button>
<button @click.prevent="delForm" v-if="item" class="block mt-4 w-64 h-10 text-white bg-red-700 rounded-lg hover:bg-red-600">Delete</button>
</form>
</div>
</div>
</template>
<script>
import { inject, ref } from 'vue'
import { create, update, del } from '../utils/websocket'
export default {
setup() {
const store = inject('store')
const item = ref('')
const name = ref('')
const logo = ref('')
const players = ref([])
const setItem = (e) => {
item.value = e._id
name.value = e.name
logo.value = e.logo
players.value = e.players
}
const addPlayer = () => {
players.value.push({
name: '',
account: '',
})
}
const reset = () => {
item.value = ''
name.value = ''
logo.value = ''
players.value = []
}
const form = () => {
if (item.value !== '') {
update('rosters', item.value, {
name: name.value,
logo: logo.value,
players: players.value,
})
} else if (name.value !== '') {
create('rosters', {
name: name.value,
logo: logo.value,
players: players.value,
})
}
reset()
}
const delForm = () => {
if (item.value) {
del('rosters', item.value)
reset()
}
}
return {
store,
item,
name,
logo,
players,
setItem,
form,
delForm,
addPlayer,
}
},
}
</script>
<style>
.item:hover {
@apply bg-gray-300 cursor-pointer;
}
.item.active {
@apply bg-gray-400;
}
</style>

29
src/router/index.js

@ -1,16 +1,33 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
import store from '../store'
const guestGuard = (from, to, next) => {
if (store.state.loggedIn === true)
next({ name: 'Home' })
else
next()
}
const authGuard = (from, to, next) => {
if (store.state.loggedIn === true)
next()
else
next({ name: 'Login' })
}
const routes = [
{
path: '/',
name: 'Home',
component: Home
name: 'Login',
component: Login,
beforeEnter: guestGuard,
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
path: '/home',
name: 'Home',
component: () => import('../views/Home.vue'),
beforeEnter: authGuard,
}
]

44
src/store.js

@ -0,0 +1,44 @@
import { reactive } from 'vue'
import axios from 'axios'
import { handleMsg, sendSub } from './utils/websocket'
const state = reactive({
token: '',
session: '',
loggedIn: false,
ws: null,
events: [],
rosters: [],
matches: [],
casters: [],
hosts: [],
streams: [],
})
const methods = {
authenticate: async () => {
return axios.post('http://localhost:5000/api/v1', {
token: state.token,
})
.then((res) => {
state.session = res.data.session
state.loggedIn = true
return true
})
},
connect: (uri) => {
state.ws = new WebSocket(`${uri}/${state.session}`)
state.ws.onopen = () => {
sendSub(state.ws)
}
state.ws.onmessage = (e) => {
const data = JSON.parse(e.data)
handleMsg(data)
}
}
}
export default {
state,
methods,
}

82
src/utils/websocket.js

@ -0,0 +1,82 @@
import store from '../store'
const events = [
'create',
'read',
'update',
'delete',
]
const channels = [
'rosters',
'events',
'matches',
'casters',
'hosts',
'streams',
]
const channelEvents = [
'info',
]
channels.forEach((x) => {
events.forEach((y) => {
channelEvents.push(`${x}:${y}`)
})
})
export const handleMsg = (msg) => {
if (channelEvents.indexOf(msg.event) !== -1) {
const ev = msg.event.split(':')
const c = ev[0]
const e = ev[1]
if (e === 'read') {
store.state[c] = msg.data
}
} else {
console.warn('received unkown event!', msg)
}
}
export const sendSub = (ws) => {
channels.forEach(c => {
const d = {
subscribe: `${c}:read`
}
ws.send(JSON.stringify(d))
})
}
export const create = (channel, data) => {
if (channels.indexOf(channel) !== -1) {
store.state.ws.send(JSON.stringify({
event: `${channel}:create`,
data,
}))
}
}
export const update = (channel, id, data) => {
if (channels.indexOf(channel) !== -1) {
store.state.ws.send(JSON.stringify({
event: `${channel}:update`,
data: {
id: id,
data: data,
},
}))
}
}
export const del = (channel, id) => {
if (channels.indexOf(channel) !== -1) {
store.state.ws.send(JSON.stringify({
event: `${channel}:delete`,
data: {
id,
},
}))
}
}

5
src/views/About.vue

@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

60
src/views/Home.vue

@ -1,5 +1,59 @@
<template>
<div class="home">
hi
<div class="flex h-screen overflow-hidden">
<div class="relative w-96 text-white bg-gray-800 py-10 flex flex-col items-center">
<h2 class="text-2xl mb-10 font-black text-red-500 uppercase">Slapdash</h2>
<p class="nav-item" @click="nav = 'dash'" :class="nav === 'dash' ? 'active' : ''">Dashboard</p>
<p class="nav-item" @click="nav = 'events'" :class="nav === 'events' ? 'active' : ''">Events</p>
<p class="nav-item" @click="nav = 'rosters'" :class="nav === 'rosters' ? 'active' : ''">Rosters</p>
<p class="nav-item" @click="nav = 'matches'" :class="nav === 'matches' ? 'active' : ''">Matches</p>
<p class="nav-item" @click="nav = 'casters'" :class="nav === 'casters' ? 'active' : ''">Casters</p>
<p class="nav-item" @click="nav = 'hosts'" :class="nav === 'hosts' ? 'active' : ''">Hosts</p>
<p class="nav-item" @click="nav = 'streams'" :class="nav === 'streams' ? 'active' : ''">Streams</p>
<img class="block w-16 h-16 absolute bottom-10" src="https://cms.aplesports.com/storage/uploads/2020/04/23/5ea178d6570e1APL_New.png" alt="APL Logo">
</div>
<div class="bg-gray-200 w-full px-10 py-4 overflow-y-auto">
<div v-if="nav === 'dash'">Coming soon</div>
<Events v-if="nav === 'events'" />
<Rosters v-if="nav === 'rosters'" />
<Matches v-if="nav === 'matches'" />
</div>
</div>
</template>
</template>
<script>
import { inject, ref } from 'vue'
import Events from '@/components/Events.vue'
import Rosters from '@/components/Rosters.vue'
import Matches from '@/components/Matches.vue'
export default {
components: {
Events,
Rosters,
Matches,
},
setup() {
const store = inject('store')
store.methods.connect('ws://localhost:5000/ws')
const nav = ref('dash')
return {
store,
nav,
}
},
}
</script>
<style>
.nav-item {
@apply flex justify-center items-center w-96 h-14;
}
.nav-item:hover {
@apply bg-gray-700 cursor-pointer;
}
.nav-item.active {
@apply bg-gray-600;
}
</style>

44
src/views/Login.vue

@ -0,0 +1,44 @@
<template>
<div class="w-screen h-screen mx-auto py-10 flex flex-col justify-center items-center">
<h1 class="text-2xl uppercase text-red-600 font-black text-center">APL Slapdash</h1>
<h2 class="my-4 text-lg">Welcome to Slapdash!</h2>
<p class="my-8">Please enter your token to continue</p>
<div class="input w-96 flex flex-col justify-center items-center">
<input :disabled="disable" class="block my-4 border border-gray-500 rounded-lg w-64 h-8 px-4" type="password" v-model="store.state.token" name="token" id="token">
<button :disabled="disable" @click.prevent="doAuth" class="block w-64 h-8 text-white bg-red-700 rounded-lg hover:bg-red-600">Submit</button>
</div>
</div>
</template>
<script>
import { inject, ref } from 'vue'
import { useRouter } from 'vue-router'
export default {
setup() {
const store = inject('store')
const disable = ref(false)
const router = useRouter()
const doAuth = async () => {
try {
disable.value = true
const res = await store.methods.authenticate()
if (res) {
router.push({ name: 'Home' })
}
} catch(e) {
console.warn(e)
} finally {
disable.value = false
}
}
return {
store,
disable,
doAuth,
}
},
}
</script>
Loading…
Cancel
Save