Skip to content
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ The following instructions will get you a copy of the project and the setting ne
- [MySQL v8.0.16](https://dev.mysql.com/downloads/mysql/)
- [MySQL Workbench v8.0.16](https://dev.mysql.com/downloads/workbench/)

<p>&nbsp;</p>

### Clone

Expand Down Expand Up @@ -374,12 +373,15 @@ $ npm run serve
- Database and model configuration, back-end automation testing and Node.js scheduler integration
- Cooperate with teammates to come up with better user stories, wireframe, ERD model and RESTful API design
- Cooperate with teammates to set up database, create seeders, and deploy the app
- Cooperate with back-end teammate to design and use our own RESTful API
- Code review for teammates


### [Mike Huang](https://github.com/smallpaes)

- Entire front-end development--Project setup, features development, and new technologies implementation
- Entire front-end development
- Project setup, features development, and new technologies implementation(Sass, Google Maps APIs, etc.)
- Pages for visitors, members, restaurants owner, and admin
- UX and UI design
- Github project creation and branch management
- Cooperate with teammates to come up with better user stories, wireframe, ERD model and RESTful API design
Expand Down
5 changes: 2 additions & 3 deletions client/src/apis/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ export default {
getUser ({ userId }) {
return apiHelper.get(`/admin/users/${userId}`)
},
getUsers ({ subscriptionStatus, name }) {
const searchParams = new URLSearchParams({ 'sub_status': subscriptionStatus, name })
console.log(`/admin/users?${searchParams.toString()}`)
getUsers ({ subscriptionStatus, name, page }) {
const searchParams = new URLSearchParams({ 'sub_status': subscriptionStatus, name, page })
return apiHelper.get(`/admin/users?${searchParams.toString()}`)
},
deleteUser ({ userId }) {
Expand Down
5 changes: 3 additions & 2 deletions client/src/components/AdminFilterPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
:has-label="false"
:placeholder="'訂單日期'"
:disabled="isLoading"
:clearable="false"
class="col-sm-6 my-1 col-md pl-md-2 pr-md-0"
@handle-date="$emit('after-date-pick', $event)"
/>
Expand Down Expand Up @@ -79,8 +80,8 @@ export default {
},
filters: {
transformName (name) {
if (name === 'active') return '已訂購'
if (name === 'inactive') return '未訂購'
if (name === 'active') return '已訂閱'
if (name === 'inactive') return '未訂閱'
return name
}
},
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/AdminOrdersTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<td>#{{ order.id }}</td>
<td>{{ order.User.name }}</td>
<td>{{ order.meals.Restaurant.name | textTruncate(10) }}</td>
<td>{{ order.date.slice(4, 8) }}</td>
<td>{{ order.date.slice(2, 6) }}</td>
<td>{{ order.time }}</td>
<td v-if="order.order_status === '取消'">
已取消
Expand Down
57 changes: 25 additions & 32 deletions client/src/components/CustomCarousel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,45 +62,38 @@ export default {
</script>

<style lang="scss" scoped>
/deep/ .VueCarousel-navigation {
/deep/ .VueCarousel-navigation-button {
display: none;
border-radius: 50%;
background-color: color(quaternary);
line-height: 8px;
color: lighten(color(secondary), 30%);
box-shadow: 0 .125rem .25rem rgba(0,0,0,.075);

&-button {
display: none;
border-radius: 50%;
background-color: color(quaternary);
line-height: 8px;
color: lighten(color(secondary), 30%);
box-shadow: 0 .125rem .25rem rgba(0,0,0,.075);

&:focus {
outline: none;
}

&:hover {
color: lighten(color(secondary), 10%);
}

@include response(md) {
display: block;
}
@include response(md) {
display: block;
}
}

&--disabled {
display: none;
}
/deep/ .VueCarousel-navigation-button:focus {
outline: none;
}

/deep/ .VueCarousel-dot {
/deep/ .VueCarousel-navigation-button:hover {
color: lighten(color(secondary), 10%);
}

&:focus {
outline: none;
}
/deep/ .VueCarousel-navigation--disabled {
display: none;
}

&-container {
@include response(md) {
display: none;
}
}
/deep/ .VueCarousel-dot:focus {
outline: none;
}

/deep/ .VueCarousel-dot-container {
@include response(md) {
display: none;
}
}
</style>
5 changes: 5 additions & 0 deletions client/src/components/CustomDatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
:not-before="new Date('1900', '12', '12')"
:editable="editable"
:disabled="disabled"
:clearable="clearable"
@input="v ? v.$touch() : $emit('handle-date', $event)"
/>
<small
Expand Down Expand Up @@ -66,6 +67,10 @@ export default {
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: true
}
},
data () {
Expand Down
9 changes: 8 additions & 1 deletion client/src/components/Navbar/AdminSideNavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ export default {
white-space: nowrap;
background-color: color(quaternary);
transition: width .2s linear;
overflow-y: scroll;
overflow-x: hidden;
z-index: 3;

// Hide scrollbar on Firefox
scrollbar-width: none;

&-brand {
@include visibleTransition(visible);

Expand All @@ -118,6 +120,11 @@ export default {
width: 100%;
}

/*Hide scrollbar on Chrome, Opera, Safari*/
&::-webkit-scrollbar {
display: none;
}

@include response(sm) {
width: 80px;
}
Expand Down
9 changes: 8 additions & 1 deletion client/src/components/Navbar/OwnerSideNavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ export default {
white-space: nowrap;
background-color: color(quaternary);
transition: width .2s linear;
overflow-y: scroll;
overflow-x: hidden;
z-index: 3;

// Hide scrollbar on Firefox
scrollbar-width: none;

&-brand {
@include visibleTransition(visible);

Expand All @@ -118,6 +120,11 @@ export default {
width: 100%;
}

/*Hide scrollbar on Chrome, Opera, Safari*/
&::-webkit-scrollbar {
display: none;
}

@include response(sm) {
width: 80px;
}
Expand Down
4 changes: 2 additions & 2 deletions client/src/utils/helpers.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import axios from 'axios'
import Swal from 'sweetalert2'

const baseURL = 'https://nextmeal.herokuapp.com/api'
// const baseURL = 'http://localhost:3000/api'
// const baseURL = 'https://nextmeal.herokuapp.com/api'
const baseURL = 'http://localhost:3000/api'

// config an instance
const axiosInstance = axios.create({
Expand Down
2 changes: 1 addition & 1 deletion client/src/views/AdminOrders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
>
<FetchMoreButton
:is-fetching="isFetching"
@fetch-more="fetchOrders(currentSearchInput, currentFilterOption, currentPage + 1)"
@fetch-more="fetchOrders(currentSearchInput, currentDate, currentFilterOption, currentPage + 1)"
/>
</div>
</div>
Expand Down
68 changes: 56 additions & 12 deletions client/src/views/AdminUsers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
:options="subscriptionStatus"
:input-placeholder="'搜尋名稱'"
:is-loading="isLoading"
@after-search="handleAfterFilter({searchInput: $event, selectedOption: currentFilterOption})"
@after-filter="handleAfterFilter({searchInput: currentSearchInput, selectedOption: $event})"
@after-search="handleAfterFilter({page: 0,searchInput: $event, selectedOption: currentFilterOption})"
@after-filter="handleAfterFilter({page: 0, searchInput: currentSearchInput, selectedOption: $event})"
>
<template v-slot:filterOption>
訂單狀態
訂閱狀態
</template>
</AdminFilterPanel>

Expand All @@ -40,11 +40,25 @@
>
<template v-if="!isLoading">
<!--User Data Table-->
<AdminUsersTable
<div
v-if="users.length > 0"
:users="users"
class="users-table"
/>
>
<AdminUsersTable

:users="users"
/>
<div
v-if="totalPage > 0 && currentPage !== totalPage"
class="btn-container mt-3 mt-md-4"
>
<FetchMoreButton
:is-fetching="isFetching"
@fetch-more="fetchUsers(currentFilterOption, currentSearchInput, currentPage + 1)"
/>
</div>
</div>

<!--Placeholder Messgae for Empty Data-->
<PlaceholderMessage
v-else
Expand All @@ -64,6 +78,7 @@ import NavbarToggler from '../components/Navbar/NavbarToggler'
import AdminFilterPanel from '../components/AdminFilterPanel'
import AdminUsersTable from '../components/AdminUsersTable.vue'
import PlaceholderMessage from '../components/Placeholder/Message'
import FetchMoreButton from '../components/Button/FetchMoreButton'
import Loader from '../components/Loader'
import adminAPI from '../apis/admin'
import { Toast } from '../utils/helpers'
Expand All @@ -75,6 +90,7 @@ export default {
AdminFilterPanel,
AdminUsersTable,
PlaceholderMessage,
FetchMoreButton,
Loader
},
data () {
Expand All @@ -83,34 +99,50 @@ export default {
subscriptionStatus: ['active', 'inactive'],
currentSearchInput: '',
currentFilterOption: '',
currentPage: 0,
totalPage: null,
isLoading: true,
isFetching: false,
navIsOpen: false
}
},
created () {
const { sub_status: subscriptionStatus = '', name = '' } = this.$route.query
this.fetchUsers({ subscriptionStatus, name })
this.fetchUsers(subscriptionStatus, name, this.currentPage + 1)
},
beforeRouteUpdate (to, from, next) {
// Reset current page
this.currentPage = 0
// clear existing data
this.users = []
const { sub_status: subscriptionStatus = '', name = '' } = to.query
this.fetchUsers({ subscriptionStatus, name })
this.fetchUsers(subscriptionStatus, name, this.currentPage + 1)
next()
},
methods: {
async fetchUsers ({ subscriptionStatus, name }) {
async fetchUsers (subscriptionStatus, name, page) {
try {
// update fetching status
this.isFetching = true
// fetch data from API
const { data, statusText } = await adminAPI.users.getUsers({ subscriptionStatus, name })
const { data, statusText } = await adminAPI.users.getUsers({ subscriptionStatus, name, page })
// error handling
if (data.status !== 'success' || statusText !== 'OK') throw new Error(data.message)
// store data
this.users = data.users
this.users = [...this.users, ...data.users]
this.subscriptionStatus = data.sub_status || this.subscriptionStatus
// update page data
this.totalPage = data.pages
this.currentPage += 1
// update loading status
this.isLoading = false
// update fetching status
this.isFetching = false
} catch (error) {
// update loading status
this.isLoading = false
// update fetching status
this.isFetching = false
// fire error messages
Toast.fire({
type: 'error',
Expand All @@ -122,10 +154,11 @@ export default {
// update loading status
this.isLoading = true
// reset data
this.currentPage = 0
this.users = []
this.currentFilterOption = data.selectedOption
this.currentSearchInput = data.searchInput
this.fetchUsers({ subscriptionStatus: this.currentFilterOption, name: this.currentSearchInput })
this.fetchUsers(this.currentFilterOption, this.currentSearchInput, this.currentPage)
}
}
}
Expand All @@ -142,4 +175,15 @@ export default {
.users {
@include controlPanelLayout;
}

.btn-container {
text-align: center;
.btn {
@include solidButton(150);

@include response(md) {
min-width: 200px;
}
}
}
</style>
Loading