@ -0,0 +1,55 @@ | |||
package Seeder | |||
import ( | |||
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Database" | |||
"git.tovijaeschke.xyz/tovi/SuddenImpactRecords/Models" | |||
) | |||
func createPost(userData Models.User) (Models.Post, error) { | |||
var ( | |||
postData Models.Post | |||
err error | |||
) | |||
postData = Models.Post{ | |||
UserID: userData.ID, | |||
Title: "Test post", | |||
Content: "Test content", | |||
FrontPage: true, | |||
Order: 1, | |||
PostLinks: []Models.PostLink{ | |||
{ | |||
Type: "Facebook", | |||
Link: "http://facebook.com/", | |||
}, | |||
}, | |||
} | |||
err = Database.CreatePost(&postData) | |||
return postData, err | |||
} | |||
func SeedPosts() { | |||
var ( | |||
userData Models.User | |||
i int | |||
err error | |||
) | |||
err = Database.DB. | |||
Model(Models.User{}). | |||
First(&userData). | |||
Error | |||
if err != nil { | |||
panic(err) | |||
} | |||
for i = 0; i <= 20; i++ { | |||
_, err = createPost(userData) | |||
if err != nil { | |||
panic(err) | |||
} | |||
} | |||
} |
@ -0,0 +1,61 @@ | |||
<template> | |||
<div class="row mb-3"> | |||
<div class="col-12"> | |||
<div class="page-nav-container"> | |||
<div class="row"> | |||
<div class="col-md-6 col-10"> | |||
<div class="input-group"> | |||
<input | |||
type="text" | |||
class="form-control" | |||
placeholder="Search..." | |||
ref="search" | |||
> | |||
<div class="input-group-append"> | |||
<button | |||
class="btn btn-dark" | |||
type="button" | |||
@click="searchFunction" | |||
> | |||
Search | |||
</button> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="col-md-6 float-right col-2"> | |||
<div class="btn-group float-right" role="group"> | |||
<router-link :to="{ name: addNewTo }"> | |||
<button | |||
type="button" | |||
class="btn btn-rounded btn-dark d-none d-md-inline-block" | |||
> | |||
<i class="fa-solid fa-plus"></i> | |||
{{ addNewLabel }} | |||
</button> | |||
<button | |||
type="button" | |||
class="btn btn-rounded btn-dark d-inline-block d-md-none" | |||
> | |||
<i class="fa-solid fa-plus"></i> | |||
</button> | |||
</router-link> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
props: { | |||
addNewTo: { type: String }, | |||
addNewLabel: { type: String }, | |||
searchFunction: { type: Function }, | |||
} | |||
} | |||
</script> |
@ -0,0 +1,156 @@ | |||
<template> | |||
<div id="admin-page-container"> | |||
<admin-navbar/> | |||
<section class="container mt-5"> | |||
<div class="row mb-3"> | |||
<div class="col-12"> | |||
<div class="page-nav-container"> | |||
<div class="btn-group" role="group"> | |||
<button | |||
type="button" | |||
class="btn btn-rounded" | |||
:class="tab === 'details' ? 'btn-dark' : 'btn-outline-dark'" | |||
@click="tab = 'details'" | |||
> | |||
Post Details | |||
</button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card shadow-2-strong card-registration"> | |||
<div class="card-body p-4 p-md-5" v-if="tab === 'details'"> | |||
<h3 class="mb-4 pb-2 pb-md-0 mb-md-5">Update Post</h3> | |||
<Form @submit="updatePost" v-slot="{ meta, errors }"> | |||
<div class="row"> | |||
<div class="col-md-8 mb-4"> | |||
<div class="form-outline"> | |||
<Field | |||
v-model="post.title" | |||
type="text" | |||
id="title" | |||
name="Title" | |||
class="form-control form-control-lg" | |||
:class="errors['Title'] ? 'invalid' : ''" | |||
rules="required"/> | |||
<label v-if="!errors['Title']" class="form-label" for="title">Title</label> | |||
<ErrorMessage name="Title" as="label" class="form-label" for="title"/> | |||
</div> | |||
</div> | |||
<div class="col-md-4 mb-4"> | |||
<div class="form-outline"> | |||
<select | |||
v-model="post.front_page" | |||
id="front_page" | |||
name="Front Page" | |||
class="form-control form-control-lg form-select"> | |||
<option :value="true">Yes</option> | |||
<option :value="false">No</option> | |||
</select> | |||
<label v-if="!errors['Front Page']" class="form-label" for="front_page">Front Page</label> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-md-4 mb-4 pb-2"> | |||
<div class="form-outline"> | |||
<date-picker | |||
v-model="post.created_at" | |||
format="dd/MM/yyyy, HH:mm" | |||
disabled="disabled" | |||
id="created_at"/> | |||
<label class="form-label" for="created_at">Created At</label> | |||
</div> | |||
</div> | |||
<div class="col-md-4 mb-4 pb-2"> | |||
<div class="form-outline"> | |||
<date-picker | |||
v-model="post.updated_at" | |||
format="dd/MM/yyyy, HH:mm" | |||
disabled="disabled" | |||
id="updated_at"/> | |||
<label class="form-label" for="updated_at">Updated At</label> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="mt-2 pt-2 right-align"> | |||
<button class="btn btn-danger btn-md" type="button"> | |||
Delete | |||
</button> | |||
<button :disabled="!meta.touched || !meta.valid" class="btn btn-primary btn-md" type="submit"> | |||
Update | |||
</button> | |||
</div> | |||
</Form> | |||
</div> | |||
</div> | |||
</section> | |||
</div> | |||
</template> | |||
<script> | |||
import AdminNavbar from '@/components/admin/components/navbar/AdminNavbar' | |||
import { Form, Field, ErrorMessage } from 'vee-validate' | |||
export default { | |||
data() { | |||
return { | |||
tab: 'details', | |||
post: {}, | |||
} | |||
}, | |||
components: { | |||
AdminNavbar, | |||
Form, | |||
Field, | |||
ErrorMessage, | |||
}, | |||
mounted () { | |||
this.getPost() | |||
}, | |||
methods: { | |||
async getPost () { | |||
try { | |||
const response = await this.axios.get(`/post/${this.$route.params.id}`) | |||
if (response.status === 200) { | |||
this.post = response.data | |||
} | |||
} catch (error) { | |||
this.$toast.error('An error occurred.') | |||
} | |||
}, | |||
async updatePost () { | |||
try { | |||
let response = await this.axios.put( | |||
`/user/${this.$route.params.id}`, | |||
{ | |||
first_name: this.user.first_name, | |||
last_name: this.user.last_name, | |||
email: this.user.email, | |||
}, | |||
) | |||
if (response.status === 200) { | |||
this.$toast.success('Successfully updated user details.'); | |||
this.setPostFromResponse(response) | |||
} | |||
} catch (error) { | |||
this.$toast.error('An error occured'); | |||
} | |||
}, | |||
} | |||
} | |||
</script> |
@ -0,0 +1,139 @@ | |||
<template> | |||
<div id="admin-page-container"> | |||
<admin-navbar/> | |||
<div class="container table-responsive mt-5 pb-5"> | |||
<admin-list-header | |||
addNewTo="AdminUsersCreate" | |||
addNewLabel="Add Post" | |||
:searchFunction="searchPosts" | |||
ref="listHeader" | |||
/> | |||
<div class="card shadow-2-strong card-registration"> | |||
<table class="table table-striped"> | |||
<thead class="thead-dark"> | |||
<tr> | |||
<th scope="col">Title</th> | |||
<th scope="col">Front Page</th> | |||
<th scope="col" class="d-none d-sm-table-cell">Created At</th> | |||
<th scope="col" class="d-none d-sm-table-cell">Published At</th> | |||
<th scope="col"></th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="post in posts" :key="post.id"> | |||
<td class="align-middle">{{ post.title }}</td> | |||
<td class="align-middle">{{ post.front_page }}</td> | |||
<td class="align-middle d-none d-sm-table-cell">{{ formatDate(post.created_at) }}</td> | |||
<td v-if="post.published_at" class="align-middle d-none d-sm-table-cell">{{ formatDate(post.published_at) }}</td> | |||
<td v-if="!post.published_at" class="align-middle d-none d-sm-table-cell">-</td> | |||
<td class="align-middle"> | |||
<router-link | |||
:to="{ name: 'AdminPostsForm', params: { id: post.id } }" | |||
> | |||
<button | |||
class="btn btn-outline-dark" | |||
> | |||
Open | |||
</button> | |||
</router-link> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<p v-if="dataEnd" class="py-2 center-align text-muted">No more data</p> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import AdminNavbar from '@/components/admin/components/navbar/AdminNavbar' | |||
import AdminListHeader from '@/components/admin/components/list/AdminListHeader.vue' | |||
export default { | |||
data() { | |||
return { | |||
posts: [], | |||
page: 0, | |||
pageSize: 15, | |||
search: '', | |||
dataEnd: false, | |||
} | |||
}, | |||
components: { | |||
AdminNavbar, | |||
AdminListHeader, | |||
}, | |||
beforeMount () { | |||
this.getInitialPosts() | |||
}, | |||
mounted () { | |||
this.axios.get('/admin/me') | |||
this.getNextPosts() | |||
}, | |||
methods: { | |||
formatDate (dateString) { | |||
const d = new Date(dateString) | |||
let hours = d.getHours(); | |||
let minutes = d.getMinutes(); | |||
const ampm = hours >= 12 ? 'pm' : 'am'; | |||
hours = hours % 12; | |||
hours = hours ? hours : 12; | |||
minutes = minutes < 10 ? '0'+minutes : minutes; | |||
const strTime = hours + ':' + minutes + ' ' + ampm; | |||
return d.getDate() + "/" + (d.getMonth()+1) + "/" + d.getFullYear() + " " + strTime; | |||
}, | |||
async getInitialPosts () { | |||
try { | |||
const response = await this.axios.get( | |||
`/post?page=${this.page}&pageSize=${this.pageSize}&search=${this.search}` | |||
) | |||
if (response.status === 200) { | |||
this.posts = response.data | |||
} | |||
} catch (error) { | |||
if (error.response.status === 404) { | |||
this.posts = {} | |||
this.dataEnd = true | |||
} | |||
} | |||
}, | |||
async getNextPosts () { | |||
window.onscroll = async () => { | |||
let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === document.documentElement.offsetHeight; | |||
if (bottomOfWindow) { | |||
try { | |||
this.page += 1 | |||
const response = await this.axios.get( | |||
`/post?page=${this.page}&pageSize=${this.pageSize}&search=${this.search}` | |||
) | |||
if (response.status === 200) { | |||
this.posts.push(...response.data) | |||
} | |||
} catch (error) { | |||
console.log(error) | |||
if (error.response.status === 404) { | |||
this.dataEnd = true | |||
} | |||
} | |||
} | |||
} | |||
}, | |||
searchPosts () { | |||
this.search = this.$refs.listHeader.$refs.search.value | |||
this.getInitialPosts() | |||
} | |||
} | |||
} | |||
</script> |