first commit

This commit is contained in:
2024-02-28 16:03:19 -05:00
commit 54ee44ba66
84 changed files with 15919 additions and 0 deletions

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM node:latest
ENV VITE_BASE_URL="http://localhost:4056"
ENV VITE_PAY_URL="http://localhost:4052"
ENV VITE_AUTO_URL="http://localhost:4053"
RUN mkdir -p /app
WORKDIR /app
COPY package*.json ./
ENV PATH /app/node_modules/.bin:$PATH
RUN npm install
COPY . /app

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support For `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.

1
env.production Normal file
View File

@@ -0,0 +1 @@
VITE_BASE_URL="https://api.freeport.cash"

15
index.html Normal file
View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Oil</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

2591
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "eamco_frontend_v2",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@kyvg/vue3-notification": "^3.1.0",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueuse/core": "^10.7.0",
"axios": "^1.6.2",
"pinia": "^2.1.7",
"v-pagination-3": "^0.1.7",
"vue": "^3.3.11",
"vue-debounce": "^5.0.0",
"vue-router": "^4.2.5",
"vuelidate": "^0.7.7"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"autoprefixer": "^10.4.16",
"daisyui": "^4.4.19",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6",
"typescript": "^5.2.2",
"vite": "^5.0.8",
"vue-tsc": "^1.8.25"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

1
public/vite.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

16
src/App.vue Normal file
View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
</script>
<template>
<html class="opensans">
<router-view />
<notifications position="top center" />
</html>
</template>
<style>
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

16
src/assets/main.css Normal file
View File

@@ -0,0 +1,16 @@
select {
-webkit-appearance: listbox !important
}
input[type=file]::-webkit-file-upload-button,
input[type=file]::file-selector-button {
/*@apply text-white bg-gray-700 hover:bg-gray-600 rounded-md font-bold text-sm cursor-pointer border-0 py-2.5 pl-4 pr-4;*/
}
.wrapper {
min-height: calc(100vh - 558px);
margin-top: 20px;
}
.WrapperPlain {
min-height: calc(100vh - 75px);
margin-top: 20px;
}

1
src/assets/stripejs.js Normal file

File diff suppressed because one or more lines are too long

5
src/assets/tailwind.css Normal file
View File

@@ -0,0 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

1
src/assets/vue.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1,34 @@
<template>
<div class="col-span-12 btn-group flex justify-center">
<ul v-show="props.showPagination" :class="props.theme.list">
<button class="btn" @click="props.setPrevPage">
<a v-bind="{...props.aProps,...props.prevProps}">{{props.texts.prevPage}}</a>
</button>
<button v-for="page in props.pages" :key="page" class="btn"
v-on="props.pageEvents(page)">
<a v-bind="props.aProps" :class="props.theme.link">{{page}}</a>
</button>
<button class="btn" @click="props.setNextPage">
<a v-bind="{...props.aProps, ...props.nextProps}">{{props.texts.nextPage}}</a>
</button>
</ul>
</div>
<div class="col-span-12 flex justify-center">
</div>
</template>
<script lang="ts">
export default {
name: 'pagination',
props: ['props']
}
</script>

8
src/decs.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
declare module "axios";
declare module "@kyvg/vue3-notification";
declare module "v-pagination-3";
declare module "vue-router";
declare module "@vuelidate/core";
declare module "@vuelidate/validators";
declare module "pinia";
declare module "@vueuse/core";

4
src/index.css Normal file
View File

@@ -0,0 +1,4 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

3
src/input.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,46 @@
<template>
<footer class="footer p-10 bg-neutral text-neutral-content mt-20">
<nav>
<h6 class="footer-title">Services</h6>
<a class="link link-hover">Branding</a>
<a class="link link-hover">Design</a>
<a class="link link-hover">Marketing</a>
<a class="link link-hover">Advertisement</a>
</nav>
<nav>
<h6 class="footer-title">Company</h6>
<a class="link link-hover">About us</a>
<a class="link link-hover">Contact</a>
<a class="link link-hover">Jobs</a>
<a class="link link-hover">Press kit</a>
</nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a class="link link-hover">Terms of use</a>
<a class="link link-hover">Privacy policy</a>
<a class="link link-hover">Cookie policy</a>
</nav>
</footer>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Footer',
data() {
return {
user: null,
}
},
mounted() {},
methods: {},
})
</script>
<style>
</style>

View File

@@ -0,0 +1,33 @@
<template>
<section>
<div v-for="user in customers" :key="user.id">
<router-link :to="{ name: 'customerProfile', params: { id: user['id'] } }">
<div class="grid grid-cols-12 bg-neutral pb-5 hover:bg-accent">
<div class="col-span-12"> {{ user['customer_first_name'] }} {{ user['customer_last_name'] }}</div>
<div class="col-span-12">
{{ user['customer_address'] }} {{ user['customer_town'] }} {{user.state}}
</div>
<div class="col-span-12"> {{user['customer_phone_number']}}</div>
</div>
</router-link>
<hr/>
</div>
</section>
</template>
<script lang="ts">
import {defineComponent} from "vue";
export default defineComponent({
name: "SearchResults",
props: ["customers"],
});
</script>

View File

@@ -0,0 +1,191 @@
<template>
<div class="navbar bg-base-100">
<div class="basis-1/4 md:basis-1/4">
<router-link :to="{ name: 'home' }">
Auburn Oil
</router-link>
</div>
<div class="basis-1/4 md:basis-1/2 justify-center text-center">
<input type="text" placeholder="Search " class="input input-bordered w-24 md:w-auto grow" v-model="searchTerm"/>
</div>
<div class="basis-1/2 md:basis-1/4 justify-end gap-5">
<router-link :to="{ name: 'customerCreate' }">
<button class="btn">Create Customer</button>
</router-link>
<div v-if="employee.id">
<router-link :to="{ name: 'employeeProfile', params: { id: employee.id } }">
<button class="btn">{{ user.user_name }}</button>
</router-link>
</div>
</div>
</div>
<div class="grid grid-cols-12 ">
<div class="grow col-start-4 col-span-6 ">
<SearchResults v-if="customers.length" :customers="customers"/>
</div>
</div>
</template>
<script lang="ts">
import {debounce} from "vue-debounce";
import {defineComponent} from "vue";
import axios from "axios";
import authHeader from "../../services/auth.header";
import SearchResults from "./SearchResults.vue";
export default defineComponent({
name: "HeaderAuth",
components: {
SearchResults,
},
created() {
this.userStatus();
},
data() {
return {
user: {
user_id: 0,
user_name: '',
},
employee: {
id: '',
user_id: '',
employee_last_name: "",
employee_first_name: "",
employee_town: "",
employee_address: "",
employee_apt: "",
employee_zip: "",
employee_birthday: "",
employee_phone_number: "",
employee_start_date: "",
employee_end_date: "",
employee_type: '',
employee_state: '',
},
loaded: false,
searchTerm: '',
customers: [],
type_of_search: 0,
};
},
watch: {
searchTerm() {
this.performSearch();
},
},
methods: {
performSearch: debounce(async function () {
console.log(this.searchTerm)
if (this.searchTerm === "") {
this.customers = [];
return;
}
if (this.searchTerm.length < 2) {
return;
}
if (this.searchTerm.startsWith("@")) {
this.type_of_search = 0
} else if (this.searchTerm.startsWith("!")) {
this.type_of_search = 1
} else if (this.searchTerm.startsWith("#")) {
this.type_of_search = 2
} else {
this.type_of_search = 2
}
const searchUrl = this.getSearchUrl();
const response = await (await fetch(searchUrl)).json();
this.customers = response;
}, 600),
getSearchUrl() {
if (this.type_of_search == 0) {
const url = "http://127.0.0.1:4056/search/customer";
const params = {
q: this.searchTerm,
};
const searchParams = new URLSearchParams(params);
return `${url}?${searchParams}`;
}
else if (this.type_of_search == 1) {
const url = "http://127.0.0.1:4056/search/customer";
const params = {
q: this.searchTerm,
};
const searchParams = new URLSearchParams(params);
return `${url}?${searchParams}`;
}
else if (this.type_of_search == 2) {
const url = "http://127.0.0.1:4056/search/customer";
const params = {
q: this.searchTerm,
};
const searchParams = new URLSearchParams(params);
return `${url}?${searchParams}`;
}
else {
const url = "http://127.0.0.1:4056/search/customer";
const params = {
q: this.searchTerm,
};
const searchParams = new URLSearchParams(params);
return `${url}?${searchParams}`;
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.employeeStatus()
this.loaded = true;
} else {
localStorage.removeItem('user');
this.$router.push('/login');
}
})
.catch(() => {
this.loaded = true;
this.$router.push('/login');
});
},
employeeStatus() {
let path = import.meta.env.VITE_BASE_URL + '/employee/userid/' + this.user.user_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.employee = response.data;
this.loaded = true;
})
},
},
});
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,56 @@
<template>
<div class="navbar bg-base-100">
<div class="basis-1/4 md:basis-1/4">
<router-link :to="{ name: 'home' }">
Auburn Oil
</router-link>
</div>
<div class="basis-1/4 md:basis-1/2 justify-center text-center">
</div>
<div class="basis-1/2 md:basis-1/4 justify-end gap-5">
<router-link :to="{ name: 'login' }">
<button class="btn">Login</button>
</router-link>
<router-link :to="{ name: 'register' }">
<button class="btn">Register</button>
</router-link>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "HeaderNoAuth",
mounted () {
},
data () {
return {
user: null,
loaded: false,
clicked: false,
hovered: false,
};
},
methods: {
},
});
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,67 @@
<template>
<div class="navbar bg-base-100">
<div class="basis-1/4 md:basis-1/4">
<router-link :to="{ name: 'home' }">
Auburn Oil
</router-link>
</div>
<div class="basis-1/4 md:basis-1/2 justify-center text-center">
<input type="search" placeholder="Search " class="input input-bordered w-24 md:w-auto" v-model="searchTerm"/>
</div>
<SearchResults v-if="customers.length" :customers="customers" />
<div class="basis-1/2 md:basis-1/4 justify-end gap-5">
<router-link :to="{ name: 'customerCreate' }">
<button class="btn">Create Customer</button>
</router-link>
<!-- <div v-if="employee.id">-->
<!-- <router-link :to="{ name: 'employeeProfile', params: { id: employee.id } }">-->
<!-- <button class="btn">{{ user.user_name }}</button>-->
<!-- </router-link>-->
<!-- </div>-->
</div>
</div>
</template>
<script lang="ts">
import { debounce } from "vue-debounce";
import SearchResults from "./SearchResults.vue";
import { ref, watch } from "vue";
const searchTerm = ref("");
const customers = ref([]);
const getSearchUrl = () => {
const url = "https://dummyjson.com/products/search";
const params = {
q: searchTerm.value,
limit: "5",
};
const searchParams = new URLSearchParams(params);
return `${url}?${searchParams}`;
};
const performSearch = debounce(async () => {
console.log("searching")
if (searchTerm.value === "") {
customers.value = [];
return;
}
if (searchTerm.value.length < 2) {
return;
}
const searchUrl = getSearchUrl();
const response = await (await fetch(searchUrl)).json();
customers.value = response.products;
}, 600);
watch(searchTerm, () => {
performSearch();
});
</script>

View File

@@ -0,0 +1,107 @@
<template>
<div class="drawer sm:drawer-open">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle"/>
<div class="drawer-content flex flex-col items-center justify-center ">
</div>
<div class="drawer-side">
<label for="my-drawer-2" aria-label="close sidebar" class="drawer-overlay"></label>
<ul class="menu p-4 w-80 min-h-full bg-base-200 text-base-content">
<!-- Sidebar content here -->
<router-link :to="{ name: 'home' }">
<div class=" hover:underline py-1 px-5 font-bold">Home</div>
</router-link>
<div class="font-bold text-lg text-gray-500 pt-5">Customer</div>
<li>
<router-link :to="{ name: 'customer' }">
<div class=" hover:underline py-1">All Customers</div>
</router-link>
<router-link :to="{ name: 'customerCreate' }">
<div class=" hover:underline py-1">Create Customer</div>
</router-link>
</li>
<div class="font-bold text-lg text-gray-500 pt-5">Delivery</div>
<li>
<router-link :to="{ name: 'delivery' }">
<div class=" hover:underline py-1">Waiting Deliveries</div>
</router-link>
<router-link :to="{ name: 'delivery' }">
<div class=" hover:underline py-1">Out for Delivery</div>
</router-link>
<router-link :to="{ name: 'deliveryTicketsMissing' }">
<div class=" hover:underline py-1">Delivered Tickets</div>
</router-link>
<router-link :to="{ name: 'deliveryTicketsMissing' }">
<div class=" hover:underline py-1">Finalized Tickets</div>
</router-link>
</li>
<div class="font-bold text-lg text-gray-500 pt-5">Service</div>
<li>
<router-link :to="{ name: 'service' }">
<div class=" hover:underline py-1">Service</div>
</router-link>
</li>
<div class="font-bold text-lg text-gray-500 pt-5">Automatics</div>
<li>
<router-link :to="{ name: 'auto' }">
<div class=" hover:underline py-1">Automatics</div>
</router-link>
</li>
<div class="font-bold text-lg text-gray-500 pt-5">Employees</div>
<li>
<router-link :to="{ name: 'employee' }">
<div class=" hover:underline py-1">Employees</div>
</router-link>
</li>
<div class="font-bold text-lg text-gray-500 pt-5">Admin</div>
<li>
<router-link :to="{ name: 'oilprice' }">
<div class=" hover:underline py-1">Oil Pricing</div>
</router-link>
</li>
<li>
<router-link :to="{ name: 'serviceprice' }">
<div class=" hover:underline py-1">Service Pricing</div>
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
export default defineComponent({
name: "SideBar",
mounted() {
},
data() {
return {};
},
methods: {},
});
</script>
<style scoped>
</style>

14
src/main.ts Normal file
View File

@@ -0,0 +1,14 @@
import { createApp } from 'vue';
import './assets/tailwind.css'
import './assets/main.css'
import App from './App.vue';
import router from './router';
import Notifications from '@kyvg/vue3-notification';
import Pagination from 'v-pagination-3';
import { createPinia } from 'pinia';
const app = createApp(App)
app.use(createPinia());
app.use(router)
.component('pagination', Pagination);
app.use(Notifications).mount('#app')

222
src/pages/Index.vue Normal file
View File

@@ -0,0 +1,222 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex text-2xl mb-5">
Welcome {{ employee.employee_first_name }} {{ employee.employee_last_name }}!
</div>
<div class="grid grid-cols-12 gap-5">
<div class="col-span-12 bg-neutral ">
<div class="grid grid-cols-12 p-5">
<div class="col-span-12 font-bold text-xl">Todays stats</div>
<div class="col-span-6 py-2"> Total Deliveries: {{delivery_count}}</div>
<div class="col-span-6 py-2"> Total Service Calls: {{service_count}}</div>
</div>
</div>
<div class="col-span-6 bg-neutral" >
<div class="grid grid-cols-12 p-5 ">
<div class="col-span-12 font-bold text-xl">Todays Oil Price</div>
<div class="col-span-12 py-2"> Price / Gallon: {{today_oil_price}}</div>
<div class="col-span-12 py-2"> Same Day: ${{same_day}}</div>
<div class="col-span-12 py-2"> Prime: ${{prime}}</div>
</div>
</div>
<div class="col-span-6 bg-neutral" >
<div class="grid grid-cols-12 p-5 ">
<div class="col-span-12 font-bold text-xl">Todays Service Price</div>
<div class="col-span-12 py-2"> Price / hour: ${{price_hourly}}</div>
<div class="col-span-12 py-2"> Emergency Fee: ${{emergency_fee}}</div>
<div class="col-span-12 py-2"> Emergency Price / hour: ${{emergency_rate}}</div>
<div class="col-span-12 py-2"> Cleaning ${{cleaning}}</div>
<div class="col-span-12 py-2"> Out of Oil: ${{out_of_oil}}</div>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../services/auth.header'
import Header from '../layouts/headers/headerauth.vue'
import SideBar from '../layouts/sidebar/sidebar.vue'
import Footer from '../layouts/footers/footer.vue'
export default defineComponent({
name: 'Home',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
delivery_count: 0,
service_count: 0,
today_oil_price: '',
same_day: '',
price_hourly: '',
emergency_fee: '',
emergency_rate: '',
prime: '',
cleaning: '',
out_of_oil: '',
user: {
user_id: 0,
user_name: '',
},
employee: {
id: '',
user_id: '',
employee_last_name: "",
employee_first_name: "",
employee_town: "",
employee_address: "",
employee_apt: "",
employee_zip: "",
employee_birthday: "",
employee_phone_number: "",
employee_start_date: "",
employee_end_date: "",
employee_type: '',
employee_state: '',
},
loaded: false,
}
},
created() {
this.userStatus()
this.today_delivery_count()
this.today_service_count()
this.today_price_oil()
this.today_price_service()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.employeeStatus()
} else {
localStorage.removeItem('user');
this.$router.push('/login');
}
})
},
employeeStatus() {
let path = import.meta.env.VITE_BASE_URL + '/employee/userid/' + this.user.user_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.employee = response.data;
this.loaded = true;
})
},
today_delivery_count() {
let path = import.meta.env.VITE_BASE_URL + '/stats/delivery/count/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.delivery_count = response.data.data;
})
},
today_service_count() {
let path = import.meta.env.VITE_BASE_URL + '/stats/service/count/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.service_count = response.data.data;
})
},
today_price_oil() {
let path = import.meta.env.VITE_BASE_URL + '/info/price/oil'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.today_oil_price = response.data.price;
})
},
today_price_service() {
let path = import.meta.env.VITE_BASE_URL + '/info/price/service'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.same_day = response.data.same_day;
this.price_hourly = response.data.price_hourly;
this.emergency_fee = response.data.emergency_fee;
this.emergency_rate = response.data.emergency_rate;
this.prime = response.data.prime;
this.cleaning = response.data.cleaning;
this.out_of_oil = response.data.out_of_oil;
})
},
},
})
</script>
<style scoped>
</style>
<script setup lang="ts">
</script>

View File

@@ -0,0 +1,186 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">
Add oil Price
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full"
enctype="multipart/form-data"
@submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Price Customer</label>
<input v-model="CreateOilForm.basicInfo.price_for_customer"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Todays Price"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Price Employee</label>
<input v-model="CreateOilForm.basicInfo.price_for_employee"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Todays Price Employee"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2"> Price from Supplier</label>
<input v-model="CreateOilForm.basicInfo.price_from_supplier"
class="input input-bordered w-full max-w-xs"
id="prime" type="text" placeholder="Price Prime"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Create Price
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'ServicePrice',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
CreateOilForm: {
basicInfo: {
price_from_supplier: '',
price_for_customer: '',
price_for_employee: '',
},
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
},
},
mounted() {
this.getCurrentPrices()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCurrentPrices() {
let path = import.meta.env.VITE_BASE_URL + "/admin/oil/get";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.CreateOilForm.basicInfo.price_from_supplier = response.data.price_from_supplier;
this.CreateOilForm.basicInfo.price_for_customer = response.data.price_for_customer;
this.CreateOilForm.basicInfo.price_for_employee = response.data.price_for_employee;
}
})
},
CreatePricing(payload: {
price_from_supplier: string;
price_for_customer: string;
price_for_employee: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/admin/oil/create";
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "update",
text: "Prices have been updated!",
type: "success",
});
this.$router.push({name: "oilprice"});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
price_from_supplier: this.CreateOilForm.basicInfo.price_from_supplier,
price_for_customer: this.CreateOilForm.basicInfo.price_for_customer,
price_for_employee: this.CreateOilForm.basicInfo.price_for_employee,
};
this.CreatePricing(payload);
},
},
})
</script>
<style scoped>
</style>

21
src/pages/admin/routes.ts Normal file
View File

@@ -0,0 +1,21 @@
import OilPrice from '../admin/oilprice.vue';
import ServicePrice from "./serviceprice.vue";
const adminRoutes = [
{
path: '/oilprice',
name: 'oilprice',
component: OilPrice,
},
{
path: '/serviceprice',
name: 'serviceprice',
component: ServicePrice,
},
]
export default adminRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,217 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">
Change Pricing
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full"
enctype="multipart/form-data"
@submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Hourly Service Rate</label>
<input v-model="CreateServiceForm.basicInfo.price_service_hour"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Hourly Rate"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Hourly Emergency Service Rate</label>
<input v-model="CreateServiceForm.basicInfo.price_emergency_service_hour"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Emergency Rate"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Emergency Fee </label>
<input v-model="CreateServiceForm.basicInfo.price_emergency_call"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="After hour/ same day Fee"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Out of Oil Price</label>
<input v-model="CreateServiceForm.basicInfo.price_emergency_call"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Out of oil price"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Prime Price</label>
<input v-model="CreateServiceForm.basicInfo.price_prime"
class="input input-bordered w-full max-w-xs"
id="prime" type="text" placeholder="Price Prime"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Create Price
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'ServicePrice',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
CreateServiceForm: {
basicInfo: {
price_service_hour: '',
price_emergency_service_hour: '',
price_emergency_call: '',
price_out_of_oil: '',
price_prime: '',
},
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
},
},
mounted() {
this.getCurrentPrices()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCurrentPrices() {
let path = import.meta.env.VITE_BASE_URL + "/admin/service/get";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.CreateServiceForm.basicInfo.price_service_hour = response.data.price_service_hour;
this.CreateServiceForm.basicInfo.price_emergency_service_hour = response.data.price_emergency_service_hour;
this.CreateServiceForm.basicInfo.price_emergency_call = response.data.price_emergency_call;
this.CreateServiceForm.basicInfo.price_out_of_oil = response.data.price_out_of_oil;
this.CreateServiceForm.basicInfo.price_prime = response.data.price_prime;
}
})
},
CreatePricing(payload: {
price_service_hour: string;
price_emergency_service_hour: string;
price_emergency_call: string;
price_out_of_oil: string;
price_prime: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/admin/service/create";
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "update",
text: "Prices have been updated!",
type: "success",
});
this.$router.push({name: "serviceprice"});
}
if (response.data.error) {
notify({
title: "update",
text: "error updating prices :(",
type: "success",
});
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
price_service_hour: this.CreateServiceForm.basicInfo.price_service_hour,
price_emergency_service_hour: this.CreateServiceForm.basicInfo.price_emergency_service_hour,
price_emergency_call: this.CreateServiceForm.basicInfo.price_emergency_call,
price_out_of_oil: this.CreateServiceForm.basicInfo.price_out_of_oil,
price_prime: this.CreateServiceForm.basicInfo.price_prime,
};
this.CreatePricing(payload);
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,166 @@
<template>
<Header />
<div class="WrapperPlain">
<div class="container max-w-3xl mx-auto text-white">
<div class="mt-5 mb-5 px-10 ">
<nav class="rounded-md w-full">
<ol class="list-reset flex">
<li>
<router-link :to="{ name: 'home' }">
<a class="text-primary hover:text-primary ">Home</a>
</router-link>
</li>
<li>
<span class="text-gray-500 mx-2">/</span>
</li>
</ol>
</nav>
</div>
<div class="mx-auto max-w-lg flex items-center justify-center mb-10 mt-20 px-5">
<form class="bg-neutral rounded-md px-8 pt-6 pb-8 mb-4 w-full" @submit.prevent="onSubmit">
<div class="mb-4 text-center text-[28px] ">
Change Password
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Enter New Password</label>
<input v-model="ChangePasswordForm.new_password" class="rounded w-full py-2 px-3 input-primary text-black"
id="password" type="password" placeholder="Password" />
<span v-if="v$.ChangePasswordForm.new_password.$error" class="text-red-600 text-center">
{{ v$.ChangePasswordForm.new_password.$errors[0].$message }}
</span>
</div>
<div class="mb-6">
<label class="block text-white text-sm font-bold mb-2">Confirm New Password</label>
<input v-model="ChangePasswordForm.password_confirm" class="rounded w-full py-2 px-3 input-primary text-black"
id="passwordtwo" type="password" autocomplete="off" placeholder="Confirm Password" />
<span v-if="v$.ChangePasswordForm.password_confirm.$error" class="text-red-600 text-center">
{{ v$.ChangePasswordForm.password_confirm.$errors[0].$message }}
</span>
</div>
<div class="flex items-center justify-center mb-6">
<button
class="bg-primary hover:bg-zinc-400 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit">
Update
</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import axios from "axios";
import { notify } from "@kyvg/vue3-notification";
import useValidate from "@vuelidate/core";
import { required, minLength } from "@vuelidate/validators";
import Header from "../../layouts/headers/headerauth.vue";
import authHeader from "../../services/auth.header";
export default defineComponent({
name: "changePassword",
components: {
Header,
},
data () {
return {
v$: useValidate(),
user: null,
user_admin: 0,
loaded: false,
ChangePasswordForm: {
new_password: "",
password_confirm: "",
},
};
},
validations () {
return {
ChangePasswordForm: {
new_password: { required, minLength: minLength(6) },
password_confirm: { required, minLength: minLength(6) },
},
};
},
created () {
this.userStatus();
},
methods: {
userStatus () {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response:any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.$router.push({ name: "login" });
});
},
sendWordRequest (payLoad: { new_password: string; password_confirm: string }) {
let path = import.meta.env.VITE_BASE_URL + "/auth/change-password";
axios({
method: "post",
url: path,
data: payLoad,
withCredentials: true,
headers: authHeader(),
}).then((response:any) => {
if (response.data.ok) {
notify({
title: "Authorization",
text: "Success!",
type: "success",
});
this.$router.push({ name: "login" });
}
if (response.data.error) {
notify({
title: "Authorization Error",
text: response.data.error,
type: "error",
});
}
})
.catch(() => {
notify({
title: "Authorization",
text: "Invalid Credentials.",
type: "error",
});
});
},
onSubmit () {
const payLoad = {
new_password: this.ChangePasswordForm.new_password,
password_confirm: this.ChangePasswordForm.password_confirm,
};
this.v$.$validate(); // checks all inputs
if (this.v$.$invalid) {
notify({
title: "Authorization",
text: "Form Failure",
type: "error",
});
} else {
this.sendWordRequest(payLoad);
}
},
},
});
</script>

197
src/pages/auth/login.vue Normal file
View File

@@ -0,0 +1,197 @@
<template>
<Header />
<div class="WrapperPlain">
<div class="max-w-7xl mx-auto ">
<div class="mx-auto max-w-lg flex items-center justify-center mt-4">
<form
class="rounded-md px-8 pt-6 pb-8 mb-4 w-full bg-neutral"
@submit.prevent="onSubmit"
>
<div class="mb-4 text-center text-[28px] ">Login</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Username</label>
<input
v-model="loginForm.username"
class="rounded w-full py-2 px-3 input-primary text-black"
id="username"
type="text"
placeholder="Username"
/>
</div>
<span
v-if="v$.loginForm.username.$error"
class="text-red-600 text-center"
>
{{ v$.loginForm.username.$errors[0].$message }}
</span>
<div class="">
<label class="block text-white text-sm font-bold mb-2">
Password
</label>
<input
v-model="loginForm.password"
class="rounded w-full py-2 px-3
input-primary text-black"
id="password"
type="password"
autocomplete="off"
placeholder="Password"
/>
<span
v-if="v$.loginForm.password.$error"
class="text-red-600 text-center"
>
{{ v$.loginForm.password.$errors[0].$message }}
</span>
</div>
<div class="flex items-center justify-center mb-6 mt-4">
<button
class="bg-primary hover:bg-zinc-400 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Sign In
</button>
</div>
<div class="flex flex-col justify-center mt-5">
<router-link
:to="{ name: 'lostPassword' }"
class="text-center font-bold text-sm text-white hover:text-accent"
>Forgot Password?</router-link
>
</div>
<div class="flex flex-col justify-center mt-5">
<router-link
:to="{ name: 'register' }"
class="text-center font-bold text-sm text-white hover:text-accent"
>Register Here</router-link
>
</div>
</form>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue"
import axios from "axios"
import { notify } from "@kyvg/vue3-notification"
import useValidate from "@vuelidate/core"
import { required, minLength } from "@vuelidate/validators"
import Header from "../../layouts/headers/headernoauth.vue";
import authHeader from "../../services/auth.header.ts"
export default defineComponent({
name: "Login",
components: { Header },
data() {
return {
v$: useValidate(),
user: null,
loginForm: {
username: "",
password: "",
},
};
},
mounted() {
this.userStatus();
},
validations() {
return {
loginForm: {
password: { required, minLength: minLength(6) },
username: { required, minLength: minLength(6) },
},
};
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response:any) => {
if (response.data.ok) {
this.$router.push({ name: "home" });
}
})
.catch(() => {});
},
sendLogin(payLoad: { username: string; password: string }) {
let path = import.meta.env.VITE_BASE_URL + "/auth/login"
axios({
method: "post",
url: path,
data: payLoad,
withCredentials: true,
})
.then((response:any) => {
if (response.data.user) {
localStorage.setItem("auth_token", response.data.token);
localStorage.setItem("auth_user", response.data.user);
this.$router.push({ name: "home" });
notify({
title: "Authorization",
text: "You have been logged in!",
type: "success",
});
}
else if (response.data.locked) {
notify({
title: "Authorization",
text: "Account has been locked for security reasons. Please unlock.",
type: "error",
});
this.$router.push({ name: "lostPassword" });
}
else {
notify({
title: "Authorization",
text: "Login Failure!",
type: "error",
});
}
})
.catch(() => {
notify({
title: "Authorization",
text: "Login Failure!",
type: "error",
});
});
},
onSubmit() {
const payLoad = {
username: this.loginForm.username,
password: this.loginForm.password,
};
this.v$.$validate(); // checks all inputs
if (this.v$.$invalid) {
notify({
title: "Authorization",
text: "Form Error: Fields must be filled out correctly",
type: "error",
});
} else {
this.sendLogin(payLoad);
}
},
},
});
</script>

View File

@@ -0,0 +1,131 @@
<template>
<Header />
<div class="WrapperPlain">
<div class="container max-w-3xl mx-auto text-white">
<div class="mt-5 mb-5">
<nav class="rounded-md w-full">
<ol class="list-reset flex">
<li>
<router-link :to="{ name: 'home' }">
<a class="text-primary hover:text-primary ">Home</a>
</router-link>
</li>
<li>
<span class="text-gray-500 mx-2">/</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mx-auto max-w-lg flex items-center justify-center mb-10 mt-12 text-white">
<form class="bg-neutral rounded-md px-8 pt-6 pb-8 mb-4 w-full" @submit.prevent="onSubmit">
<div class="mb-4 text-center text-[20px] ">
In order to unlock your account, please enter your username/email below.
</div>
<div class="my-5">
<input v-model="ForgotForm.username" class="rounded w-full py-2 px-3 input-primary text-black" type="text"
autocomplete="off" placeholder="Username" />
<span v-if="v$.ForgotForm.username.$error" class="text-red-600 text-center">
{{ v$.ForgotForm.username.$errors[0].$message }}
</span>
</div>
<div class="my-5">
<input v-model="ForgotForm.email" class="rounded w-full py-2 px-3 input-primary text-black" type="text"
autocomplete="off" placeholder="Email" />
<span v-if="v$.ForgotForm.email.$error" class="text-red-600 text-center">
{{ v$.ForgotForm.email.$errors[0].$message }}
</span>
</div>
<div class="flex p-md justify-center">
<button
class="bg-primary hover:bg-zinc-400 text-white font-bold py-2 px-4 rounded focus:outline-blue-300 focus:outline-none focus:shadow-outline"
type="submit">
Confirm
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue"
import axios from "axios"
import { notify } from "@kyvg/vue3-notification"
import useValidate from "@vuelidate/core"
import { required } from "@vuelidate/validators"
import Header from "../../layouts/headers/headernoauth.vue"
export default defineComponent({
name: "lostPassword",
components: {
Header,
},
data () {
return {
v$: useValidate(),
ForgotForm: {
email: "",
username: "",
},
}
},
validations () {
return {
ForgotForm: {
email: { required },
username: { required },
},
}
},
methods: {
sendWordRequest (payLoad: {
email: string;
username: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/auth/unlock-account"
axios({
method: "post",
url: path,
data: payLoad,
})
.then((response:any) => {
if (response.data.ok) {
localStorage.setItem("auth_token", response.data.token);
localStorage.setItem("auth_user", response.data.user);
this.$router.push({ name: "changePassword" });
}
})
.catch(() => {
notify({
title: "Authorization",
text: "Form Error",
type: "error",
});
});
},
onSubmit () {
const payLoad = {
email: this.ForgotForm.email,
username: this.ForgotForm.username,
}
this.v$.$validate(); // checks all inputs
if (this.v$.$invalid) {
notify({
title: "Authorization",
text: "Form Failure",
type: "error",
});
}
else {
this.sendWordRequest(payLoad);
}
},
},
});
</script>
<style type="ts" scoped></style>

165
src/pages/auth/register.vue Normal file
View File

@@ -0,0 +1,165 @@
<template>
<Header />
<div class="WrapperPlain">
<div class="container mx-auto max-w-lg text-white">
<div class="mx-auto flex items-center justify-center ">
<form class="bg-neutral rounded-md px-8 pt-6 pb-8 mb-4 mt-4 w-full" method="POST" @submit.prevent="onSubmit">
<div class="mb-4 text-center text-[28px] ">Register</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2" for="username">Username</label>
<input v-model="registerForm.username" class="rounded w-full py-2 px-3 input-primary text-black" id="username"
type="text" placeholder="Login Username" />
<span v-if="v$.registerForm.username.$error" class="text-red-600 text-center">
{{ v$.registerForm.username.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2" for="username">Email</label>
<input v-model="registerForm.email" class="rounded w-full py-2 px-3 input-primary text-black" id="email"
type="text" placeholder="Email" />
<span v-if="v$.registerForm.email.$error" class="text-red-600 text-center">
{{ v$.registerForm.email.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2" for="password">Password</label>
<input v-model="registerForm.password" class="rounded w-full py-2 px-3 input-primary text-black" id="password"
type="password" autocomplete="off" placeholder="Password" />
<span v-if="v$.registerForm.password.$error" class="text-red-600 text-center">
{{ v$.registerForm.password.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2" for="password_confirm">Confirm Password</label>
<input v-model="registerForm.password_confirm" class="rounded w-full py-2 px-3 input-primary text-black"
id="password" type="password" autocomplete="off" placeholder="Confirm Password" />
<span v-if="v$.registerForm.password_confirm.$error" class="text-red-600 text-center">
{{ v$.registerForm.password_confirm.$errors[0].$message }}
</span>
</div>
<div class="flex items-center justify-center mb-6">
<button
class="bg-primary hover:bg-zinc-400 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit">
Register
</button>
</div>
<div class="flex flex-col justify-center">
<router-link :to="{ name: 'lostPassword' }"
class="text-center font-bold text-sm text-blue-500 hover:text-blue-800">Forgot Password?</router-link>
</div>
<div class="flex flex-col justify-center mt-5">
<router-link :to="{ name: 'login' }"
class="text-center font-bold text-sm text-blue-500 hover:text-blue-800">Login Here</router-link>
</div>
</form>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import axios from "axios";
import { notify } from "@kyvg/vue3-notification";
import { useVuelidate } from '@vuelidate/core';
import { required, email, minLength, sameAs } from "@vuelidate/validators";
import Header from "../../layouts/headers/headernoauth.vue";
export default defineComponent({
name: "Register",
components: { Header },
data () {
return {
v$: useVuelidate(),
isAuthenticated: false,
registerForm: {
username: "",
email: "",
password: "",
password_confirm: "",
},
};
},
mounted () {
},
validations () {
return {
registerForm: {
password: { required, minLength: minLength(6) },
username: { required, minLength: minLength(6) },
email: { email, required },
password_confirm: {
required,
minLength: minLength(6),
sameAs: sameAs(this.registerForm.password),
},
},
};
},
methods: {
onSubmit () {
const payLoad = {
username: this.registerForm.username,
password: this.registerForm.password,
email: this.registerForm.email,
};
this.v$.$validate(); // checks all inputs
if (this.v$.$invalid) {
notify({
title: "Authorization",
text: "Form Failure; Fields must be filled our correctly.",
type: "error",
});
} else {
this.Register(payLoad);
}
},
Register (payLoad: {
username: string;
password: string;
email: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/auth/register";
axios({
method: "post",
url: path,
data: payLoad,
withCredentials: true,
})
.then((response:any) => {
console.log(response.data)
if (response.data.error) {
notify({
title: "Authorization",
text: response.data.error,
type: "error",
});
};
if (response.data.ok) {
localStorage.setItem("auth_user", response.data.user);
localStorage.setItem("auth_token", response.data.token);
this.$router.push({ name: "home" });
notify({
title: "Authorization",
text: "Success",
type: "success",
});
}
})
},
},
});
</script>
<style scoped></style>

34
src/pages/auth/routes.ts Normal file
View File

@@ -0,0 +1,34 @@
import Login from '../auth/login.vue';
import Register from '../auth/register.vue';
import changePassword from '../auth/changepassword.vue';
import lostPassword from '../auth/lostpassword.vue';
const authRoutes = [
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/register',
name: 'register',
component: Register,
},
{
path: '/lostpassword',
name: 'lostPassword',
component: lostPassword,
},
{
path: '/changepassword',
name: 'changePassword',
component: changePassword,
},
]
export default authRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,172 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'delivery' }">
Delivery
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Automatics </div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Due Date</th>
<th>Status</th>
<th>Town</th>
<th>Name</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']">
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_name'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>
{{ oil['expected_delivery_date'] }}
</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
export default defineComponent({
name: 'AutomaticHome',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,16 @@
import AutomaticHome from './home.vue';
const autoRoutes = [
{
path: '/auto',
name: 'auto',
component: AutomaticHome,
},
]
export default autoRoutes
//sourceMappingURL=index.ts.map

309
src/pages/card/addcard.vue Normal file
View File

@@ -0,0 +1,309 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">
Add Credit Card for {{ customer.customer_last_name }}
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full"
enctype="multipart/form-data"
@submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Main Card</label>
<input v-model="CreateCardForm.basicInfo.main_card"
class="checkbox"
id="fill"
type="checkbox"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Name on Card</label>
<input v-model="CreateCardForm.basicInfo.card_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Name on Card"/>
<span v-if="v$.CreateCardForm.basicInfo.card_name.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.card_name.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Card Number</label>
<input v-model="CreateCardForm.basicInfo.card_number"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Card Number"/>
<span v-if="v$.CreateCardForm.basicInfo.card_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.card_number.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expiration Month</label>
<select
v-model="CreateCardForm.basicInfo.expiration_month"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>01</option>
<option>02</option>
<option>03</option>
<option>04</option>
<option>05</option>
<option>06</option>
<option>07</option>
<option>08</option>
<option>09</option>
<option>10</option>
<option>11</option>
<option>12</option>
</select>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expiration Year</label>
<select
v-model="CreateCardForm.basicInfo.expiration_year"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>2024</option>
<option>2025</option>
<option>2026</option>
<option>2027</option>
<option>2028</option>
<option>2029</option>
<option>2030</option>
</select>
<span v-if="v$.CreateCardForm.basicInfo.expiration_year.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.expiration_year.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Type of Card</label>
<select
v-model="CreateCardForm.basicInfo.type_of_card"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>Visa</option>
<option>MasterCard</option>
<option>Discover</option>
<option>American Express</option>
</select>
<span v-if="v$.CreateCardForm.basicInfo.type_of_card.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.type_of_card.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Security Number</label>
<input v-model="CreateCardForm.basicInfo.security_number"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Back of card"/>
<span v-if="v$.CreateCardForm.basicInfo.security_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.security_number.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Save Credit Card
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'AddCardCreate',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
customer: {
id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
CreateCardForm: {
basicInfo: {
card_name: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
card_number:'',
main_card: false,
},
},
}
},
validations() {
return {
CreateCardForm: {
basicInfo: {
card_name: {required, minLength: minLength(1)},
expiration_month: {required, minLength: minLength(1)},
expiration_year: {required, minLength: minLength(1)},
security_number: {required, minLength: minLength(1)},
type_of_card: {required, minLength: minLength(1)},
card_number: {required, minLength: minLength(1)},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
},
},
mounted() {
this.getCustomer(this.$route.params.id)
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
CreateCard(payload: {
card_name: string;
expiration_month: string;
expiration_year: string;
type_of_card: string;
security_number: string;
card_number: string;
main_card: boolean;
}) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/create/" + this.customer.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.$router.push({name: "customerProfile", params: { id: this.customer.id }});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
card_name: this.CreateCardForm.basicInfo.card_name,
card_number: this.CreateCardForm.basicInfo.card_number,
expiration_month: this.CreateCardForm.basicInfo.expiration_month,
expiration_year: this.CreateCardForm.basicInfo.expiration_year,
type_of_card: this.CreateCardForm.basicInfo.type_of_card,
security_number: this.CreateCardForm.basicInfo.security_number,
main_card: this.CreateCardForm.basicInfo.main_card,
};
this.CreateCard(payload);
},
},
})
</script>
<style scoped>
</style>

382
src/pages/card/editcard.vue Normal file
View File

@@ -0,0 +1,382 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">
Credit Card Customer: {{ customer }}
</div>
<div class="text-[20px]">
Card Id: {{card.id}}
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full"
enctype="multipart/form-data"
@submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Main Card</label>
<input v-model="CreateCardForm.basicInfo.main_card"
class="checkbox"
id="fill"
type="checkbox"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Name on Card</label>
<input v-model="CreateCardForm.basicInfo.card_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Name on Card"/>
<span v-if="v$.CreateCardForm.basicInfo.card_name.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.card_name.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Card Number</label>
<input v-model="CreateCardForm.basicInfo.card_number"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Card Number"/>
<span v-if="v$.CreateCardForm.basicInfo.card_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.card_number.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expiration Month</label>
<select
v-model="CreateCardForm.basicInfo.expiration_month"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>01</option>
<option>02</option>
<option>03</option>
<option>04</option>
<option>05</option>
<option>06</option>
<option>07</option>
<option>08</option>
<option>09</option>
<option>10</option>
<option>11</option>
<option>12</option>
</select>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expiration Year</label>
<select
v-model="CreateCardForm.basicInfo.expiration_year"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>2024</option>
<option>2025</option>
<option>2026</option>
<option>2027</option>
<option>2028</option>
<option>2029</option>
<option>2030</option>
</select>
<span v-if="v$.CreateCardForm.basicInfo.expiration_year.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.expiration_year.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Type of Card</label>
<select
v-model="CreateCardForm.basicInfo.type_of_card"
class="input input-bordered w-full max-w-xs"
id="Month"
>
<option>Visa</option>
<option>MasterCard</option>
<option>Discover</option>
<option>American Express</option>
</select>
<span v-if="v$.CreateCardForm.basicInfo.type_of_card.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.type_of_card.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Security Number</label>
<input v-model="CreateCardForm.basicInfo.security_number"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Back of card"/>
<span v-if="v$.CreateCardForm.basicInfo.security_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCardForm.basicInfo.security_number.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Edit Card
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import { notify } from "@kyvg/vue3-notification";
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'EditCard',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: '',
},
customer: {
id: 0,
customer_last_name: '',
customer_first_name: '',
customer_town: '',
customer_state: '',
customer_zip: '',
customer_first_call: '',
customer_email: '',
customer_automatic: '',
customer_phone_number: '',
customer_home_type: '',
customer_apt: '',
customer_address: '',
},
card: {
id: '',
card_name: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
main_card: '',
user_id: '',
},
card_id: null,
customer_id: null,
CreateCardForm: {
basicInfo: {
card_name: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
card_number: '',
main_card: false,
},
},
}
},
validations() {
return {
CreateCardForm: {
basicInfo: {
card_name: {required, minLength: minLength(1)},
expiration_month: {required, minLength: minLength(1)},
expiration_year: {required, minLength: minLength(1)},
security_number: {required, minLength: minLength(1)},
type_of_card: {required, minLength: minLength(1)},
card_number: {required, minLength: minLength(1)},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getCard(this.$route.params.id);
},
},
mounted() {
this.getCard(this.$route.params.id)
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user.id;
}
})
.catch(() => {
this.user.id = '';
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer_id = response.data.user_id;
this.customer.customer_last_name= response.data.customer_last_name;
this.customer.customer_first_name = response.data.customer_first_name;
this.customer.customer_town = response.data.customer_town;
this.customer.customer_state = response.data.customer_state;
this.customer.customer_zip = response.data.customer_zip;
this.customer.customer_first_call = response.data.customer_first_call;
this.customer.customer_email = response.data.customer_email;
this.customer.customer_automatic = response.data.customer_automatic;
this.customer.customer_phone_number = response.data.customer_phone_number;
this.customer.customer_home_type = response.data.customer_home_type;
this.customer.customer_apt = response.data.customer_last_name;
this.customer.customer_address = response.data.customer_last_name;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getCard (card_id:any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id ;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.CreateCardForm.basicInfo.card_name= response.data.card.card_name;
this.CreateCardForm.basicInfo.expiration_month= response.data.card.expiration_month;
this.CreateCardForm.basicInfo.expiration_year= response.data.card.expiration_year;
this.CreateCardForm.basicInfo.type_of_card= response.data.card.type_of_card;
this.CreateCardForm.basicInfo.security_number= response.data.card.security_number;
this.CreateCardForm.basicInfo.main_card= response.data.card.main_card;
this.CreateCardForm.basicInfo.card_number= response.data.card.card_number;
this.user.id = response.data.card.user_id
this.card.id=response.data.card.id;
this.card.user_id=response.data.card.user_id;
this.card.card_name= response.data.card.card_name
this.card.expiration_month=response.data.card.expiration_month;
this.card.expiration_year=response.data.card.expiration_year;
this.card.type_of_card=response.data.card.type_of_card;
this.card.security_number=response.data.card.security_number;
this.card.main_card=response.data.card.main_card;
this.getCustomer(response.data.card.user_id)
}
})
},
editCard(payload: {
card_name: string;
expiration_month: string;
expiration_year: string;
type_of_card: string;
security_number: string;
main_card: boolean;
}) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/edit/" + this.$route.params.id ;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
console.log(response.data)
console.log(this.user.id)
this.$router.push({name: "customerProfile", params: { id: this.card.user_id }});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
card_name: this.CreateCardForm.basicInfo.card_name,
expiration_month: this.CreateCardForm.basicInfo.expiration_month,
expiration_year: this.CreateCardForm.basicInfo.expiration_year,
type_of_card: this.CreateCardForm.basicInfo.type_of_card,
security_number: this.CreateCardForm.basicInfo.security_number,
card_number: this.CreateCardForm.basicInfo.card_number,
main_card: this.CreateCardForm.basicInfo.main_card,
};
this.editCard(payload);
},
},
})
</script>
<style scoped>
</style>

207
src/pages/card/home.vue Normal file
View File

@@ -0,0 +1,207 @@
<template>
<Header />
<div class="flex">
<div class="">
<SideBar />
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
<router-link :to="{ name: 'customerCreate' }">
<button class="btn">Create Customer</button>
</router-link>
</div>
<div class="overflow-x-auto">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Card Type</th>
<th>Card Number</th>
<th>Expiration</th>
<th>Main Card</th>
<th></th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="card in cards" :key="card['id']">
<td>
<router-link :to="{ name: 'cardview', params: { id: card['id'] } }">
{{ card['name_on_card'] }}
</router-link>
</td>
<td>{{ card['type_of_card'] }}</td>
<td>{{ card['name_on_card'] }}</td>
<td>{{ card['expiration_month'] }} / {{ card['expiration_year'] }}</td>
<td>{{ card['main_card'] }} </td>
<td class="flex gap-5">
<router-link :to="{ name: 'cardview', params: { id: card['id'] } }">
Oil
</router-link>
<router-link :to="{ name: 'cardedit', params: { id: card['id'] } }">
Service
</router-link>
<div @click="removeCard(card['id'])">x
Remove Card
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage" :options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import axios from 'axios'
import { notify } from "@kyvg/vue3-notification";
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
export default defineComponent({
name: 'CardHome',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
customer: null,
customer_id: null,
cards: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
},
},
created() {
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
console.log("here")
this.get_all_cards(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
this.customer_id = response.data.user_id;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
get_all_cards(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.cards = response.data
console.log(response.data)
})
},
removeCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/remove/' + card_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Deletion",
text: "Card Removed",
type: "success",
});
}
})
},
},
})
</script>
<style scoped></style>

29
src/pages/card/routes.ts Normal file
View File

@@ -0,0 +1,29 @@
import CardHome from '../card/home.vue';
import AddCardCreate from '../card/addcard.vue';
import EditCard from "./editcard.vue";
const cardRoutes = [
{
path: '/card',
name: 'cardhome',
component: CardHome,
},
{
path: '/card/add/:id',
name: 'cardadd',
component: AddCardCreate,
},
{
path: '/card/edit/:id',
name: 'cardedit',
component: EditCard,
},
]
export default cardRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,328 @@
<template>
<Header/>
<div v-if="user">
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class="w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Create a customer</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="text-[18px] mt-5 mb-5">General Info</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2"> First Name</label>
<input v-model="CreateCustomerForm.basicInfo.customer_first_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="First Name"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_first_name.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_first_name.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2"> Last Name</label>
<input v-model="CreateCustomerForm.basicInfo.customer_last_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Last Name"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_last_name.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_last_name.$errors[0].$message }}
</span>
</div>
<div class="flex gap-5">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Type</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="customer_type"
v-model="CreateCustomerForm.basicInfo.customer_home_type">
<option class="text-white" v-for="(customer, index) in custList"
:key="index"
:value="customer['value']">
{{ customer['text'] }}
</option>
</select>
</div>
</div>
<div class="text-[18px] mt-5 mb-5">Customer Address</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Phone Number</label>
<input v-model="CreateCustomerForm.basicInfo.customer_phone_number"
class="input input-bordered w-full max-w-xs"
id="phone number" type="tel" placeholder="Phone Number" @input="acceptNumber()" />
<span v-if="v$.CreateCustomerForm.basicInfo.customer_phone_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_phone_number.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Street Address</label>
<input v-model="CreateCustomerForm.basicInfo.customer_address"
class="input input-bordered w-full max-w-xs"
id="address" type="text" placeholder="Address"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_address.$error"
class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_address.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 mb-5 md:mb-5">
<input v-model="CreateCustomerForm.basicInfo.customer_apt"
class="input input-bordered w-full max-w-xs"
id="apt" type="text" placeholder="Apt, suite, unit, building, floor, etc"/>
</div>
<div class="col-span-12 md:col-span-4 mb-20 md:mb-5 ">
<label class="block text-white text-sm font-bold mb-2">Town</label>
<input v-model="CreateCustomerForm.basicInfo.customer_town"
class="input input-bordered w-full max-w-xs"
id="town" type="text" placeholder="Town"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_town.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_town.$errors[0].$message }}
</span>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">State</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="customer_state"
v-model="CreateCustomerForm.basicInfo.customer_state">
<option class="text-white" v-for="(state, index) in stateList"
:key="index"
:value="state['value']">
{{ state['text'] }}
</option>
</select>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_state.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_state.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Zip Code</label>
<input v-model="CreateCustomerForm.basicInfo.customer_zip"
class="input input-bordered w-full max-w-xs"
id="zip" type="text" placeholder="Zip"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_zip.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_zip.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Email</label>
<input v-model="CreateCustomerForm.basicInfo.customer_email"
class="input input-bordered w-full max-w-xs"
id="email" type="text" placeholder="Email"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_email.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_email.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Automatic</label>
<input v-model="CreateCustomerForm.basicInfo.customer_automatic"
class="checkbox"
id="automatic"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Create Customer
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {email, minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'CustomerCreate',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
stateList: [],
x: '',
custList: [],
new_user_id: 0,
CreateCustomerForm: {
basicInfo: {
customer_last_name: "",
customer_first_name: "",
customer_town: "",
customer_apt: "",
customer_home_type: "",
customer_zip: "",
customer_automatic: "",
customer_email: "",
customer_phone_number: "",
customer_state: "",
customer_address: "",
},
},
}
},
validations() {
return {
CreateCustomerForm: {
basicInfo: {
customer_last_name: {required, minLength: minLength(1)},
customer_first_name: {required, minLength: minLength(1)},
customer_town: {required, minLength: minLength(1)},
customer_home_type: {required},
customer_zip: {required, minLength: minLength(5)},
customer_email: {email, required},
customer_phone_number: {required},
customer_state: {required},
customer_address: {required},
},
},
};
},
created() {
this.userStatus()
},
mounted() {
this.getCustomerTypeList();
this.getStatesList();
},
methods: {
acceptNumber() {
let x = this.CreateCustomerForm.basicInfo.customer_phone_number.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
if (x){
this.CreateCustomerForm.basicInfo.customer_phone_number = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
}
else {
this.CreateCustomerForm.basicInfo.customer_phone_number = ''
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
CreateCustomer(payload: {
customer_last_name: string;
customer_first_name: string;
customer_town: string;
customer_zip: string;
customer_email: string;
customer_phone_number: string;
customer_address: string;
customer_apt: string;
customer_automatic: string;
customer_home_type: string,
customer_state: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/customer/create";
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.new_user_id = response.data.user.user_id
this.$router.push({ name: 'customerProfile', params: { id: this.new_user_id } });
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
customer_last_name: this.CreateCustomerForm.basicInfo.customer_last_name,
customer_first_name: this.CreateCustomerForm.basicInfo.customer_first_name,
customer_town: this.CreateCustomerForm.basicInfo.customer_town,
customer_zip: this.CreateCustomerForm.basicInfo.customer_zip,
customer_email: this.CreateCustomerForm.basicInfo.customer_email,
customer_phone_number: this.CreateCustomerForm.basicInfo.customer_phone_number,
customer_automatic: this.CreateCustomerForm.basicInfo.customer_automatic,
customer_home_type: this.CreateCustomerForm.basicInfo.customer_home_type,
customer_state: this.CreateCustomerForm.basicInfo.customer_state,
customer_apt: this.CreateCustomerForm.basicInfo.customer_apt,
customer_address: this.CreateCustomerForm.basicInfo.customer_address,
};
this.CreateCustomer(payload);
},
getCustomerTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/customertype";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.custList = response.data;
})
.catch(() => {
});
},
getStatesList() {
let path = import.meta.env.VITE_BASE_URL + "/query/states";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.stateList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped>
</style>

371
src/pages/customer/edit.vue Normal file
View File

@@ -0,0 +1,371 @@
<template>
<Header/>
<div v-if="user">
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class="w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Edit customer: {{ customer.account_number }}</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="text-[18px] mt-5 mb-5">General Info</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2"> First Name</label>
<input v-model="CreateCustomerForm.basicInfo.customer_first_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="First Name"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_first_name.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_first_name.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2"> Last Name</label>
<input v-model="CreateCustomerForm.basicInfo.customer_last_name"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="Last Name"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_last_name.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_last_name.$errors[0].$message }}
</span>
</div>
<div class="flex gap-5">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Type</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="customer_type"
v-model="CreateCustomerForm.basicInfo.customer_home_type">
<option class="text-white" v-for="(customer, index) in custList"
:key="index"
:value="customer['value']">
{{ customer['text'] }}
</option>
</select>
</div>
</div>
<div class="text-[18px] mt-5 mb-5">Customer Address</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Phone Number</label>
<input v-model="CreateCustomerForm.basicInfo.customer_phone_number"
class="input input-bordered w-full max-w-xs"
id="phone number" type="text" placeholder="Phone Number" @input="acceptNumber()"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_phone_number.$error"
class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_phone_number.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Street Address</label>
<input v-model="CreateCustomerForm.basicInfo.customer_address"
class="input input-bordered w-full max-w-xs"
id="address" type="text" placeholder="Address"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_address.$error"
class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_address.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 mb-5 md:mb-5">
<input v-model="CreateCustomerForm.basicInfo.customer_apt"
class="input input-bordered w-full max-w-xs"
id="apt" type="text" placeholder="Apt, suite, unit, building, floor, etc"/>
</div>
<div class="col-span-12 md:col-span-4 mb-20 md:mb-5 ">
<label class="block text-white text-sm font-bold mb-2">Town</label>
<input v-model="CreateCustomerForm.basicInfo.customer_town"
class="input input-bordered w-full max-w-xs"
id="town" type="text" placeholder="town"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_town.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_town.$errors[0].$message }}
</span>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">State</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="customer_state"
v-model="CreateCustomerForm.basicInfo.customer_state">
<option class="text-white" v-for="(state, index) in stateList"
:key="index"
:value="state['value']">
{{ state['text'] }}
</option>
</select>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_state.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_state.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Zip Code</label>
<input v-model="CreateCustomerForm.basicInfo.customer_zip"
class="input input-bordered w-full max-w-xs"
id="zip" type="text" placeholder="Zip"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_zip.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_zip.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Email</label>
<input v-model="CreateCustomerForm.basicInfo.customer_email"
class="input input-bordered w-full max-w-xs"
id="email" type="text" placeholder="Email"/>
<span v-if="v$.CreateCustomerForm.basicInfo.customer_email.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.customer_email.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Automatic</label>
<input v-model="CreateCustomerForm.basicInfo.customer_automatic"
class="checkbox"
id="automatic"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Edit Customer
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {email, minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'CustomerEdit',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
stateList: [],
custList: [],
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_address: '',
customer_home_type: 0,
customer_phone_number: '',
account_number: '',
},
CreateCustomerForm: {
basicInfo: {
customer_last_name: "",
customer_first_name: "",
customer_town: "",
customer_apt: "",
customer_home_type: "",
customer_zip: "",
customer_automatic: "",
customer_email: "",
customer_phone_number: "",
customer_state: "",
customer_address: "",
},
},
}
},
validations() {
return {
CreateCustomerForm: {
basicInfo: {
customer_last_name: {required, minLength: minLength(1)},
customer_first_name: {required, minLength: minLength(1)},
customer_town: {required, minLength: minLength(1)},
customer_home_type: {required},
customer_zip: {required, minLength: minLength(5)},
customer_email: {email, required},
customer_phone_number: {required},
customer_state: {required},
customer_address: {required},
},
},
};
},
created() {
this.userStatus()
this.getCustomer(this.$route.params.id)
},
mounted() {
this.getCustomerTypeList();
this.getStatesList();
},
methods: {
acceptNumber() {
let x = this.CreateCustomerForm.basicInfo.customer_phone_number.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
if (x) {
this.CreateCustomerForm.basicInfo.customer_phone_number = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
} else {
this.CreateCustomerForm.basicInfo.customer_phone_number = '';
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
// gets the item from parameter router
getCustomer(userid: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + userid;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.customer = response.data;
this.CreateCustomerForm.basicInfo.customer_last_name = response.data.customer_last_name;
this.CreateCustomerForm.basicInfo.customer_first_name = response.data.customer_first_name;
this.CreateCustomerForm.basicInfo.customer_town = response.data.customer_town;
this.CreateCustomerForm.basicInfo.customer_state = response.data.customer_state;
this.CreateCustomerForm.basicInfo.customer_zip = response.data.customer_zip;
this.CreateCustomerForm.basicInfo.customer_automatic = response.data.customer_automatic;
this.CreateCustomerForm.basicInfo.customer_phone_number = response.data.customer_phone_number;
this.CreateCustomerForm.basicInfo.customer_home_type = response.data.customer_home_type;
this.CreateCustomerForm.basicInfo.customer_apt = response.data.customer_apt;
this.CreateCustomerForm.basicInfo.customer_email = response.data.customer_email;
this.CreateCustomerForm.basicInfo.customer_address = response.data.customer_address;
}
})
},
editItem(payload: {
customer_last_name: string;
customer_first_name: string;
customer_town: string;
customer_zip: string;
customer_email: string;
customer_phone_number: string;
customer_automatic: string;
customer_home_type: string,
customer_state: string;
customer_address: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/customer/edit/" + this.customer.id;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.$router.push({name: "customerProfile", params: {id: this.customer.id}});
}
;
if (response.data.error) {
this.$router.push("/");
}
;
})
},
onSubmit() {
let payload = {
customer_last_name: this.CreateCustomerForm.basicInfo.customer_last_name,
customer_first_name: this.CreateCustomerForm.basicInfo.customer_first_name,
customer_town: this.CreateCustomerForm.basicInfo.customer_town,
customer_zip: this.CreateCustomerForm.basicInfo.customer_zip,
customer_email: this.CreateCustomerForm.basicInfo.customer_email,
customer_phone_number: this.CreateCustomerForm.basicInfo.customer_phone_number,
customer_automatic: this.CreateCustomerForm.basicInfo.customer_automatic,
customer_home_type: this.CreateCustomerForm.basicInfo.customer_home_type,
customer_state: this.CreateCustomerForm.basicInfo.customer_state,
customer_address: this.CreateCustomerForm.basicInfo.customer_address,
};
this.editItem(payload);
},
getCustomerTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/customertype";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.custList = response.data;
})
.catch(() => {
});
},
getStatesList() {
let path = import.meta.env.VITE_BASE_URL + "/query/states";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.stateList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped>
</style>
<script setup lang="ts">
</script>

186
src/pages/customer/home.vue Normal file
View File

@@ -0,0 +1,186 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Town</th>
<th>Automatic</th>
<th>Phone Number</th>
<th></th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="person in customers" :key="person['id']">
<td>
<router-link :to="{ name: 'customerProfile', params: { id: person['id'] } }">
{{ person['customer_first_name'] }} {{ person['customer_last_name'] }}
</router-link>
</td>
<td>{{ person['customer_town'] }}</td>
<td>
<div v-if="person['customer_automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>{{ person['customer_phone_number'] }}</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryCreate', params: { id: person['id'] } }" class="cursor-pointer underline hover:text-blue-300">
Oil
</router-link>
<router-link :to="{ name: 'serviceCreate', params: { id: person['id'] } }" class="cursor-pointer underline hover:text-blue-300">
Service
</router-link>
<router-link :to="{ name: 'customerEdit', params: { id: person['id'] } }" class="cursor-pointer underline hover:text-blue-300">
Edit
</router-link>
<router-link :to="{ name: 'customerProfile', params: { id: person['id'] } }" class="cursor-pointer underline hover:text-blue-300">
View
</router-link>
<a @click.prevent="deleteCustomer(person['id'])" class="cursor-pointer underline hover:text-blue-300">
Delete
</a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
export default defineComponent({
name: 'CustomerHome',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
customers: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.customers = [];
this.get_customers(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_customers(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.customers = response.data
})
},
deleteCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/delete/' + user_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then(() => {
this.get_customers(1)
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,553 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
<div class=" w-full mt-10" v-if="customer !== null">
<div class="grid grid-cols-12 gap-5">
<div class="col-span-4 bg-neutral p-5 ">
<img src="../../../assets/images/user_placeholder.png"
alt="Drone Image"
width="200"
height="250"/>
</div>
<div class="col-span-8 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex justify-evenly pb-5">
<div class="btn">
<router-link :to="{ name: 'deliveryCreate', params: { id: customer.id } }"
class="cursor-pointer underline hover:text-blue-300">
Create Delivery
</router-link>
</div>
<div class="btn">
<router-link :to="{ name: 'serviceCreate', params: { id: customer.id } }"
class="cursor-pointer underline hover:text-blue-300">
Create Service
</router-link>
</div>
<div class="btn">
<router-link :to="{ name: 'customerEdit', params: { id: customer.id } }" class="">
Edit Customer
</router-link>
</div>
</div>
<div class="col-span-12 font-bold flex pb-5 text-lg">{{ customer.account_number }}</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_address }}
<div v-if="customer.customer_apt != 'None'">
{{ customer.customer_apt }}
</div>
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex text-2xl">
Stats
</div>
<div class="col-span-6">
<div class="col-span-12 py-2 font-bold">Delivery</div>
<div class="col-span-12 py-2">
Total Delivery Orders: 0
</div>
<div class="col-span-12 py-2">
Total Gallons: 0
</div>
<div class="col-span-12 py-2">
Last Delivery: 0
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 py-2 font-bold">Service</div>
<div class="col-span-12 py-2">
Total Service Calls: 0
</div>
<div class="col-span-12 py-2">
Last Service Call: 0
</div>
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-6 font-bold flex text-2xl">
Credit Cards
</div>
<div class="col-span-6 font-bold flex ">
<router-link :to="{ name: 'cardadd', params: { id: customer.user_id } }">
<button class="btn">Add Credit Card</button>
</router-link>
</div>
<div class="col-span-12 font-bold flex">
<div class="text-red-600" v-if="credit_cards_count == 0">
No Cards on File! Cash Customer till card added.
</div>
<div v-else>
{{ credit_cards_count }} credit card(s) on file.
</div>
</div>
<div v-for="card in credit_cards" class="col-span-12">
<div class="flex flex-row ">
<div v-if="card.main_card" class="basis-1/3 p-2">
<div class="bg-accent rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ card.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex justify-between">
<a @click.prevent="editCard(card.id)" class="cursor-pointer underline hover:text-blue-300">Edit
Card</a>
<a @click.prevent="removeCard(card.id)" class="cursor-pointer underline hover:text-blue-300">Remove
Card</a>
</div>
</div>
</div>
<div v-else class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ card.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex justify-between">
<a @click.prevent="editCard(card.id)" class="cursor-pointer underline hover:text-blue-300">Edit
Card</a>
<a @click.prevent="removeCard(card.id)" class="cursor-pointer underline hover:text-blue-300">Remove
Card</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-6 font-bold flex text-2xl">
Financial
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex text-2xl">Orders</div>
</div>
<div class="grid grid-cols-12 ">
<div role="tablist" class="tabs tabs-bordered">
<input type="radio" name="my_tabs_1" role="tab" class="tab" aria-label="Deliveries" checked/>
<div role="tabpanel" class="tab-content pt-10">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Status</th>
<th>Town</th>
<th>Name</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']">
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_name'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
</td>
</tr>
</tbody>
</table>
</div>
<input type="radio" name="my_tabs_1" role="tab" class="tab" aria-label="Service"/>
<div role="tabpanel" class="tab-content pt-10">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Customer Name</th>
<th>Status</th>
<th>Service Type</th>
<th>Scheduled Date</th>
<th>Tech Name</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="service in service_orders" :key="service['id']">
<td>
{{ service['customer_first_name'] }} {{ service['customer_last_name'] }}
</td>
<td>
<div v-if="service['status'] == 0">Waiting/not paid</div>
<div v-else-if="service['status'] == 1">Paid /waiting</div>
<div v-else-if="service['status'] == 2">Scheduled Today</div>
<div v-else-if="service['status'] == 3">Completed/Unpaid</div>
<div v-else-if="service['status'] == 4">Completed/Paid</div>
<div v-else></div>
</td>
<td>
<div v-if="service['service_type'] == 0">General</div>
<div v-else-if="service['service_type'] == 1">Cleaning / Tuneup</div>
<div v-else-if="service['service_type'] == 2">No Heat</div>
<div v-else-if="service['service_type'] == 3">Install</div>
<div v-else-if="service['service_type'] == 4">Call Back</div>
<div v-else-if="service['service_type'] == 5">Quote</div>
<div v-else-if="service['service_type'] == 6">Emergency</div>
<div v-else></div>
</td>
<td>{{ service['scheduled_date'] }}</td>
<td>
<div v-if="service['payment_type'] == 0">Cash C.O.D</div>
<div v-else-if="service['payment_type'] == 1">Credit</div>
<div v-else-if="service['payment_type'] == 2">Stripe</div>
<div v-else-if="service['payment_type'] == 3">Cash/Credit</div>
<div v-else></div>
</td>
<td>
{{ service['tech_first_name'] }} {{ service['tech_last_name'] }}
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'serviceEdit', params: { id: service['id'] } }">
<button class="btn">Edit</button>
</router-link>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import PaginationComp from "../../../components/pagination.vue";
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'CustomerProfile',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
credit_cards: [
{
id: 0,
name_on_card: '',
main_card: false,
card_number: '',
expiration_month: '',
type_of_card: '',
last_four_digits: '',
expiration_year: '',
}
],
credit_cards_count: 0,
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_address: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
account_number: '',
},
deliveries: [],
service_orders: [],
delivery_page: 1,
delivery_perPage: 50,
delivery_recordsLength: 0,
delivery_options: {
delivery_edgeNavigation: false,
delivery_format: false,
delivery_template: PaginationComp
},
service_page: 1,
service_perPage: 50,
service_recordsLength: 0,
service_options: {
service_edgeNavigation: false,
service_format: false,
service_template: PaginationComp
}
}
},
created() {
this.userStatus()
this.getCreditCards(this.$route.params.id)
this.getCreditCardsCount(this.$route.params.id)
},
mounted() {
this.getCustomer(this.$route.params.id)
this.getCustomerService(this.$route.params.id, this.service_page)
this.getCustomerDelivery(this.$route.params.id, this.delivery_page)
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
},
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.getCustomer(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(userid: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.customer = response.data
})
},
getCreditCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/' + user_id;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.credit_cards = response.data
})
},
getCreditCardsCount(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/onfile/' + user_id;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.credit_cards_count = response.data.cards
})
},
getCustomerService(userid: any, service_page: any) {
let path = import.meta.env.VITE_BASE_URL + '/service/customer/' + userid + '/' + service_page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.service_orders = response.data
})
},
getCustomerDelivery(userid: any, delivery_page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/customer/' + userid + '/' + delivery_page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
editCard(card_id: any) {
this.$router.push({name: "cardedit", params: {id: card_id}});
},
removeCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/card/remove/' + card_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then(() => {
this.getCreditCards(this.$route.params.id)
this.getCreditCardsCount(this.$route.params.id)
notify({
title: "Card Status",
text: "Card Removed",
type: "Success",
});
})
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,33 @@
import CustomerHome from '../customer/home.vue';
import CustomerCreate from '../customer/create.vue';
import CustomerEdit from "../customer/edit.vue";
import CustomerProfile from "./profile/home.vue"
const customerRoutes = [
{
path: '/customer',
name: 'customer',
component: CustomerHome,
},
{
path: '/customer/create',
name: 'customerCreate',
component: CustomerCreate,
},
{
path: '/customer/edit/:id',
name: 'customerEdit',
component: CustomerEdit,
},
{
path: '/customer/:id',
name: 'customerProfile',
component: CustomerProfile,
},
]
export default customerRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,368 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-12">
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex pb-5 text-lg">{{customer.account_number}}</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Create Oil Delivery
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Fill </label>
<input v-model="CreateOilOrderForm.basicInfo.customer_asked_for_fill"
class="checkbox"
id="fill"
type="checkbox"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Gallons Ordered</label>
<input v-model="CreateOilOrderForm.basicInfo.gallons_ordered"
:disabled="CreateOilOrderForm.basicInfo.customer_asked_for_fill == true"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="# gallons"/>
<span v-if="v$.CreateOilOrderForm.basicInfo.gallons_ordered.$error" class="text-red-600 text-center">
{{ v$.CreateOilOrderForm.basicInfo.gallons_ordered.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expected </label>
<input v-model="CreateOilOrderForm.basicInfo.expected_delivery_date"
class="input input-bordered w-full max-w-xs"
id="title" type="date"
min="2023-01-01" max="2030-01-01"/>
<span v-if="v$.CreateOilOrderForm.basicInfo.expected_delivery_date.$error"
class="text-red-600 text-center">
{{ v$.CreateOilOrderForm.basicInfo.expected_delivery_date.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="form-control">
<div class="label">
<span class="label-text">Delivery notes</span>
</div>
<textarea class="textarea textarea-bordered h-24"
placeholder="Describe any thing given from the customer .."
v-model="CreateOilOrderForm.basicInfo.dispatcher_notes_taken"></textarea>
</label>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Prime</label>
<input v-model="CreateOilOrderForm.basicInfo.prime"
class="checkbox"
id="prime"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Same Day </label>
<input v-model="CreateOilOrderForm.basicInfo.same_day"
class="checkbox"
id="same_day"
type="checkbox"/>
</div>
<div class="bg-neutral">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Cash</label>
<input v-model="CreateOilOrderForm.basicInfo.cash"
class="checkbox"
id="cash"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Credit </label>
<input v-model="CreateOilOrderForm.basicInfo.credit"
class="checkbox"
id="Credit"
type="checkbox"/>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Cards Payment</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="userCards"
v-model="CreateOilOrderForm.basicInfo.userCards">
<option class="text-white" v-for="(card, index) in userCards"
:key="index"
:value="card['id']">
{{ card['type_of_card'] }} {{ card['card_number'] }}
</option>
</select>
</div>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Create Oil Order
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'deliveryCreate',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
userCards: [],
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: '',
customer_asked_for_fill: false,
expected_delivery_date: '',
dispatcher_notes_taken: '',
prime: false,
userCards: [],
same_day: false,
credit: false,
cash: false,
credit_card_id: 0,
},
},
customer: {
id: 0,
customer_last_name: '',
customer_first_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_first_call: '',
customer_email: '',
customer_automatic: '',
customer_phone_number: '',
customer_home_type: 0,
customer_apt: '',
customer_address: '',
account_number: '',
},
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
this.getPaymentCards(this.$route.params.id);
},
},
mounted() {
this.getCustomer(this.$route.params.id)
this.getPaymentCards(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
console.log(this.customer)
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
})
.catch(() => {
});
},
CreateOilOrder(payload: {
gallons_ordered: string;
customer_asked_for_fill: boolean;
prime: boolean;
same_day: boolean;
cash: boolean;
credit: boolean;
expected_delivery_date: string;
dispatcher_notes_taken: string;
credit_card_id: any;
}) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/create/" + this.customer.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
console.log(response.data)
if (response.data.ok) {
this.$router.push({name: "payOil", params: {id: response.data.delivery_id}});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
gallons_ordered: this.CreateOilOrderForm.basicInfo.gallons_ordered,
customer_asked_for_fill: this.CreateOilOrderForm.basicInfo.customer_asked_for_fill,
expected_delivery_date: this.CreateOilOrderForm.basicInfo.expected_delivery_date,
dispatcher_notes_taken: this.CreateOilOrderForm.basicInfo.dispatcher_notes_taken,
prime: this.CreateOilOrderForm.basicInfo.prime,
same_day: this.CreateOilOrderForm.basicInfo.same_day,
cash: this.CreateOilOrderForm.basicInfo.cash,
credit: this.CreateOilOrderForm.basicInfo.credit,
credit_card_id: this.CreateOilOrderForm.basicInfo.userCards,
};
this.CreateOilOrder(payload);
},
},
})
</script>
<style scoped>
</style>

556
src/pages/delivery/edit.vue Normal file
View File

@@ -0,0 +1,556 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">
Edit Oil Delivery
</div>
<div class="bg-neutral rounded-md mx-5 my-5">
<div class="flex">
Delivery id: {{ deliveryOrder.id }}
<div class="grid grid-cols-12">
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1" v-if="deliveryOrder.payment_type==1">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.card_number }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
<div class="bg-neutral rounded-md mx-5 my-5">
<div class="flex">
Order Date: {{ deliveryOrder.when_ordered }}
</div>
<div class="flex">
Expected Delivery Date: {{ deliveryOrder.expected_delivery_date }}
</div>
<div class="flex">
Price per gallon: {{ deliveryOrder.customer_price }}
</div>
</div>
<div class="bg-neutral rounded-md mx-5 my-5">
<div class="flex">
</div>
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="bg-neutral">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Cash</label>
<input v-model="CreateOilOrderForm.basicInfo.cash"
class="checkbox"
id="cash"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Credit </label>
<input v-model="CreateOilOrderForm.basicInfo.card"
class="checkbox"
id="Credit"
type="checkbox"/>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Cards Payment</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="userCards"
v-model="CreateOilOrderForm.basicInfo.userCards">
<option class="text-white" v-for="(card, index) in userCards"
:key="index"
:value="card['id']">
{{ card['type_of_card'] }} {{ card['card_number'] }}
</option>
</select>
</div>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Delivery Status</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="delivery_status"
v-model="CreateOilOrderForm.basicInfo.delivery_status">
<option class="text-white" v-for="(delivery, index) in deliveryStatus"
:key="index"
:value="delivery['value']">
{{ delivery['text'] }}
</option>
</select>
<span v-if="v$.CreateOilOrderForm.basicInfo.delivery_status.$error" class="text-red-600 text-center">
{{ v$.CreateCustomerForm.basicInfo.delivery_status.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Fill </label>
<input v-model="CreateOilOrderForm.basicInfo.customer_asked_for_fill"
class="checkbox"
id="fill"
type="checkbox"/>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Gallons Ordered</label>
<input v-model="CreateOilOrderForm.basicInfo.gallons_ordered"
:disabled="CreateOilOrderForm.basicInfo.customer_asked_for_fill "
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="# gallons"/>
<span v-if="v$.CreateOilOrderForm.basicInfo.gallons_ordered.$error" class="text-red-600 text-center">
{{ v$.CreateOilOrderForm.basicInfo.gallons_ordered.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expected </label>
<input v-model="CreateOilOrderForm.basicInfo.expected_delivery_date"
class="input input-bordered w-full max-w-xs"
id="title" type="date"
min="2023-01-01" max="2030-01-01"/>
<span v-if="v$.CreateOilOrderForm.basicInfo.expected_delivery_date.$error"
class="text-red-600 text-center">
{{ v$.CreateOilOrderForm.basicInfo.expected_delivery_date.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold cursor-pointer label">Delivery Notes</label>
<textarea class="textarea textarea-bordered h-24 w-full"
placeholder="Describe any thing given from the customer .."
v-model="CreateOilOrderForm.basicInfo.dispatcher_notes_taken"></textarea>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Prime</label>
<input v-model="CreateOilOrderForm.basicInfo.prime"
class="checkbox"
id="prime"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Same Day </label>
<input v-model="CreateOilOrderForm.basicInfo.same_day"
class="checkbox"
id="same_day"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Edit Oil Delivery
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {minLength, required} from "@vuelidate/validators";
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryEdit',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
deliveryStatus: [],
userCards: [],
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
deliveryOrder: {
id: '',
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: '',
customer_price: '',
customer_temperature: '',
dispatcher_notes: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: 0,
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
},
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: '',
customer_asked_for_fill: false,
expected_delivery_date: '',
dispatcher_notes_taken: '',
prime: false,
same_day: false,
delivery_status: '',
userCards: [],
credit_card_id: 0,
cash: false,
card: false,
},
},
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
delivery_status: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getDeliveryForm(this.$route.params.id);
this.getDeliveryOrder(this.$route.params.id);
},
},
mounted() {
this.getDeliveryForm(this.$route.params.id)
this.getDeliveryOrder(this.$route.params.id);
this.getDeliveryStatusList();
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getDeliveryOrder(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.CreateOilOrderForm.basicInfo.gallons_ordered = response.data.delivery.delivery_gallons_ordered;
this.CreateOilOrderForm.basicInfo.customer_asked_for_fill = response.data.delivery.delivery_asked_for_fill;
this.CreateOilOrderForm.basicInfo.expected_delivery_date = response.data.delivery.delivery_expected_delivery_date;
this.CreateOilOrderForm.basicInfo.dispatcher_notes_taken = response.data.delivery.delivery_dispatcher_notes;
this.CreateOilOrderForm.basicInfo.prime = response.data.delivery.delivery_prime;
this.CreateOilOrderForm.basicInfo.same_day = response.data.delivery.delivery_same_day;
this.CreateOilOrderForm.basicInfo.delivery_status = response.data.delivery.delivery_status;
if (response.data.delivery.payment_type == 1) {
this.CreateOilOrderForm.basicInfo.userCards = response.data.delivery.payment_card_id;
}
if (response.data.delivery.delivery_prime == 1) {
this.CreateOilOrderForm.basicInfo.prime = true
}
if (response.data.delivery.delivery_same_day == 1) {
this.CreateOilOrderForm.basicInfo.same_day = true
}
if (response.data.delivery.payment_type == 0) {
this.CreateOilOrderForm.basicInfo.card = false
this.CreateOilOrderForm.basicInfo.cash = true
}
if (response.data.delivery.payment_type == 1) {
this.CreateOilOrderForm.basicInfo.card = true
this.CreateOilOrderForm.basicInfo.cash = false
}
if (response.data.delivery.payment_type == 2) {
this.CreateOilOrderForm.basicInfo.card = true
this.CreateOilOrderForm.basicInfo.cash = true
}
}
})
},
getDeliveryForm(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryOrder = response.data
this.getCustomer(this.deliveryOrder.customer_id)
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
console.log(this.deliveryOrder.payment_card_id)
this.getPaymentCards(this.deliveryOrder.customer_id);
if (this.deliveryOrder.payment_type == 1 ) {
this.getPaymentCard(this.deliveryOrder.payment_card_id)
}
if (this.deliveryOrder.payment_type == 2 ) {
this.getPaymentCard(this.deliveryOrder.payment_card_id)
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCard = response.data;
this.CreateOilOrderForm.basicInfo.userCards = response.data.id
})
.catch(() => {
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/"+ user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
})
.catch(() => {
});
},
editOilOrder(payload: {
gallons_ordered: string;
customer_asked_for_fill: boolean;
prime: boolean;
same_day: boolean;
delivery_status: string;
expected_delivery_date: string;
dispatcher_notes_taken: string;
cash: boolean;
credit: boolean;
credit_card_id: any;
}) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/edit/" + this.deliveryOrder.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.$router.push({name: "delivery"});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
getDeliveryStatusList() {
let path = import.meta.env.VITE_BASE_URL + "/query/deliverystatus";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.deliveryStatus = response.data;
})
.catch(() => {
});
},
onSubmit() {
let payload = {
gallons_ordered: this.CreateOilOrderForm.basicInfo.gallons_ordered,
customer_asked_for_fill: this.CreateOilOrderForm.basicInfo.customer_asked_for_fill,
expected_delivery_date: this.CreateOilOrderForm.basicInfo.expected_delivery_date,
dispatcher_notes_taken: this.CreateOilOrderForm.basicInfo.dispatcher_notes_taken,
prime: this.CreateOilOrderForm.basicInfo.prime,
same_day: this.CreateOilOrderForm.basicInfo.same_day,
delivery_status: this.CreateOilOrderForm.basicInfo.delivery_status,
cash: this.CreateOilOrderForm.basicInfo.cash,
credit: this.CreateOilOrderForm.basicInfo.card,
credit_card_id: this.CreateOilOrderForm.basicInfo.userCards,
};
this.editOilOrder(payload);
},
},
})
</script>
<style scoped>
</style>

204
src/pages/delivery/home.vue Normal file
View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryHome',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,76 @@
import DeliveryHome from './home.vue';
import DeliveryCreate from "./create.vue";
import DeliveryEdit from './edit.vue';
import DeliveryOrder from './view.vue';
import deliveryTicketsMissing from './update_tickets/missing_data_home.vue';
import finalizeTicket from './update_tickets/finalize_ticket.vue';
import deliveryCancelled from './viewstatus/cancelled.vue';
import deliveryIssue from './viewstatus/issue.vue';
import deliveryDelivered from './viewstatus/delivered.vue';
import deliveryOutForDelivery from './viewstatus/out_for_delivery.vue';
import deliveryWaiting from './viewstatus/waiting.vue';
const deliveryRoutes = [
{
path: '/delivery',
name: 'delivery',
component: DeliveryHome,
},
{
path: '/delivery/create/:id',
name: 'deliveryCreate',
component: DeliveryCreate,
},
{
path: '/delivery/edit/:id',
name: 'deliveryEdit',
component: DeliveryEdit,
},
{
path: '/delivery/:id',
name: 'deliveryOrder',
component: DeliveryOrder,
},
{
path: '/delivery/tickets/missing',
name: 'deliveryTicketsMissing',
component: deliveryTicketsMissing,
},
{
path: '/delivery/tickets/finalize/:id',
name: 'finalizeTicket',
component: finalizeTicket,
},
{
path: '/delivery/cancelled',
name: 'deliveryCancelled',
component: deliveryCancelled,
},
{
path: '/delivery/issue',
name: 'deliveryIssue',
component: deliveryIssue,
},
{
path: '/delivery/delivered',
name: 'deliveryDelivered',
component: deliveryDelivered,
},
{
path: '/delivery/outfordelivery',
name: 'deliveryOutForDelivery',
component: deliveryOutForDelivery,
},
{
path: '/delivery/waiting',
name: 'deliveryWaiting',
component: deliveryWaiting,
},
]
export default deliveryRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,545 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs mb-10">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md pb-5">
<div class="text-[24px]">
Finalize Oil Order # {{ deliveryOrder.id }}
</div>
<div class="grid grid-cols-12">
<div class="col-span-6">
<div class="col-span-12 font-bold">
Customer
</div>
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<div class="col-span-6 ">
<div class="flex justify-end" v-if="deliveryOrder.id ">
<router-link :to="{ name: 'deliveryEdit', params: { id: deliveryOrder.id } }">
<button class="btn">Edit Order</button>
</router-link>
</div>
</div>
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 font-bold">
Delivery Status
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
Status
</div>
<div class="col-span-12">
<div v-if="deliveryOrder.delivery_status == 0">waiting</div>
<div v-else-if="deliveryOrder.delivery_status == 1">delivered</div>
<div v-else-if="deliveryOrder.delivery_status == 2">Out for Delivery</div>
<div v-else-if="deliveryOrder.delivery_status == 3">Cancelled</div>
<div v-else-if="deliveryOrder.delivery_status == 4">Partial Delivery</div>
<div v-else-if="deliveryOrder.delivery_status == 5">misdelivery</div>
<div v-else-if="deliveryOrder.delivery_status == 6">unknown</div>
<div v-else></div>
</div>
<div class="col-span-12 font-bold mt-5">
Scheduled date/time
</div>
<div class="col-span-12 ">
{{ deliveryOrder.expected_delivery_date }}
</div>
<div class="col-span-12 font-bold mt-5">
When Called
</div>
<div class="col-span-12 ">
{{ deliveryOrder.when_ordered }}
</div>
<div class="col-span-12 font-bold mt-5">
Driver Name
</div>
<div class="col-span-12 ">
{{ deliveryOrder.driver_first_name }} {{ deliveryOrder.driver_last_name }}
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Info
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.customer_asked_for_fill==1">Fill</div>
<div v-else>Gallons delivered: {{ deliveryOrder.gallons_delivered }}</div>
</div>
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.prime==1">
Prime Required: Yes
</div>
<div v-if="deliveryOrder.prime==0">
Prime Required: No
</div>
</div>
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.same_day==1">
Same Day: Yes
</div>
<div v-if="deliveryOrder.same_day==0">
Same Day: No
</div>
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Payment
</div>
<div class="grid grid-cols-12 bg-neutral p-2">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.payment_type==0">Cash</div>
<div v-else-if="deliveryOrder.payment_type==1">Credit Card</div>
<div v-else-if="deliveryOrder.payment_type==2">Credit Card & cash</div>
<div v-else>No Payment Type Added</div>
</div>
<div class="col-span-12" v-if="deliveryOrder.payment_type==1">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-2">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
<div class="col-span-12" v-if="deliveryOrder.payment_type==2">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
<div class="col-span-12 ">Total {{deliveryMoney.total_amount}}</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Change Details
</div>
<form class="rounded-md bg-neutral " enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="grid grid-cols-12 p-5">
<div class="col-span-12 mb-5 md:mb-0 gap-10 ">
<label class="block text-white text-sm font-bold mb-2">Gallons Ordered</label>
<input v-model="CreateOilOrderForm.basicInfo.gallons_delivered"
class="input input-bordered w-full max-w-xs"
id="title" type="text" placeholder="# gallons"/>
</div>
<div class="col-span-12mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Prime</label>
<input v-model="CreateOilOrderForm.basicInfo.prime"
class="checkbox"
id="prime"
type="checkbox"/>
</div>
<div class="col-span-12 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Same Day </label>
<input v-model="CreateOilOrderForm.basicInfo.same_day"
class="checkbox"
id="same_day"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button
class="btn">
Finalize Delivery
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
export default defineComponent({
name: 'finalizeTicket',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: 0
},
CreateOilOrderForm: {
basicInfo: {
gallons_delivered: '',
prime: false,
same_day: false,
cash: false,
card: false,
userCards: []
},
},
deliveryNotesDriver: [],
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
deliveryMoney: {
time_added: '',
total_amount_oil: '',
total_amount_emergency: '',
total_amount_prime: '',
total_amount_fee: '',
total_amount: '',
},
deliveryOrder: {
id: '',
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: '',
customer_price: '',
customer_temperature: '',
dispatcher_notes: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: '',
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
this.get_delivery_amount(this.$route.params.id);
},
},
mounted() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getOilOrder(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryOrder = response.data
this.getCustomer(this.deliveryOrder.customer_id)
if (this.deliveryOrder.payment_type == 1) {
this.getPaymentCard(this.deliveryOrder.payment_card_id);
}
if (response.data.prime == 1) {
this.CreateOilOrderForm.basicInfo.prime = true
}
if (response.data.same_day == 1) {
this.CreateOilOrderForm.basicInfo.same_day = true
}
this.CreateOilOrderForm.basicInfo.gallons_delivered = response.data.gallons_delivered;
}
})
},
get_delivery_amount(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/amount/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCard = response.data;
})
.catch(() => {
});
},
getOilOrderMoney(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/money/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryMoney = response.data
}
})
},
editOilOrder(payload: {
gallons_delivered: string;
prime: boolean;
same_day: boolean;
cash: boolean;
credit: boolean;
credit_card_id: any;
}) {
let path = import.meta.env.VITE_BASE_URL + "/deliverydata/finalize/" + this.deliveryOrder.id;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Ticket is finalized",
type: "success",
});
this.$router.push({name: "deliveryTicketsMissing"});
}
if (response.data.error) {
notify({
title: "Error",
text: "Could not finalize ticket",
type: "error",
});
this.$router.push("deliveryTicketsMissing");
}
})
},
onSubmit() {
let payload = {
gallons_delivered: this.CreateOilOrderForm.basicInfo.gallons_delivered,
prime: this.CreateOilOrderForm.basicInfo.prime,
same_day: this.CreateOilOrderForm.basicInfo.same_day,
cash: this.CreateOilOrderForm.basicInfo.cash,
credit: this.CreateOilOrderForm.basicInfo.card,
credit_card_id: this.CreateOilOrderForm.basicInfo.userCards,
};
this.editOilOrder(payload);
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,145 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']">
<router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }}</td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td class="flex gap-5" v-if="oil['delivery_status'] == 1">
<router-link :to="{ name: 'finalizeTicket', params: { id: oil['id'] } }">
<button class="btn">Finalize</button>
</router-link>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
export default defineComponent({
name: 'deliveryTicketsMissing',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [
],
}
},
created() {
this.userStatus()
},
mounted() {
this.get_oil_orders()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders() {
let path = import.meta.env.VITE_BASE_URL + '/deliverydata/pending';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
},
})
</script>
<style scoped>
</style>

436
src/pages/delivery/view.vue Normal file
View File

@@ -0,0 +1,436 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md pb-5">
<div class="text-[24px]">
View Oil Order # {{ deliveryOrder.id }}
</div>
<div class="grid grid-cols-12">
<div class="col-span-6">
<div class="col-span-12 font-bold">
Customer
</div>
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<div class="col-span-6 ">
<div class="flex justify-end" v-if="deliveryOrder.id ">
<router-link :to="{ name: 'deliveryEdit', params: { id: deliveryOrder.id } }">
<button class="btn">Edit Order</button>
</router-link>
</div>
</div>
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 font-bold">
Delivery Status
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
Status
</div>
<div class="col-span-12">
<div v-if="deliveryOrder.delivery_status == 0">waiting</div>
<div v-else-if="deliveryOrder.delivery_status == 1">delivered</div>
<div v-else-if="deliveryOrder.delivery_status == 2">Out for Delivery</div>
<div v-else-if="deliveryOrder.delivery_status == 3">Cancelled</div>
<div v-else-if="deliveryOrder.delivery_status == 4">Partial Delivery</div>
<div v-else-if="deliveryOrder.delivery_status == 5">misdelivery</div>
<div v-else-if="deliveryOrder.delivery_status == 6">unknown</div>
<div v-else></div>
</div>
<div class="col-span-12 font-bold mt-10">
Scheduled date/time
</div>
<div class="col-span-12 ">
{{ deliveryOrder.expected_delivery_date }}
</div>
<div class="col-span-12 font-bold mt-10">
When Called
</div>
<div class="col-span-12 ">
{{ deliveryOrder.when_ordered }}
</div>
<div class="col-span-12 font-bold mt-10">
Driver Name
</div>
<div class="col-span-12 ">
{{ deliveryOrder.driver_first_name }} {{ deliveryOrder.driver_last_name }}
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Amount
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.customer_asked_for_fill==1">Fill</div>
<div v-else>{{ deliveryOrder.gallons_ordered }}</div>
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Payment
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.payment_type==0">Cash</div>
<div v-else-if="deliveryOrder.payment_type==1">Credit Card</div>
<div v-else-if="deliveryOrder.payment_type==2">Credit Card & cash</div>
<div v-else>No Payment Type Added</div>
</div>
<div class="col-span-12" v-if="deliveryOrder.payment_type==1">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
<div class="col-span-12" v-if="deliveryOrder.payment_type==2">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Info
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.prime==1">
Prime Required: Yes
</div>
<div v-if="deliveryOrder.prime==0">
Prime Required: No
</div>
</div>
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.same_day==1">
Same Day: Yes
</div>
<div v-if="deliveryOrder.same_day==0">
Same Day: No
</div>
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Notes
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="deliveryOrder.dispatcher_notes!='None'">
{{ deliveryOrder.dispatcher_notes }}
</div>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
export default defineComponent({
name: 'deliveryOrder',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: 0
},
deliveryNotesDriver: [],
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
deliveryMoney: {
time_added: '',
total_amount_oil: '',
total_amount_emergency: '',
total_amount_prime: '',
total_amount_fee: '',
total_amount: '',
},
deliveryOrder: {
id: '',
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: '',
customer_price: '',
customer_temperature: '',
dispatcher_notes: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: '',
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
},
},
mounted() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCard = response.data;
})
.catch(() => {
});
},
getOilOrder(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryOrder = response.data
this.getCustomer(this.deliveryOrder.customer_id)
if (this.deliveryOrder.payment_type == 1) {
this.getPaymentCard(this.deliveryOrder.payment_card_id);
}
}
})
},
getOilOrderMoney(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/money/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryMoney = response.data
}
})
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryCancelled',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/issue/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/cancelled/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryDelivered',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delivered/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryIssue',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/issue/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryOutForDelivery',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/outfordelivery/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,204 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Oil Deliveries</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Town</th>
<th>Address</th>
<th>Gallons</th>
<th>Date</th>
<th>Automatic</th>
<th>Prime</th>
<th>Same Day</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="oil in deliveries" :key="oil['id']"> <router-link :to="{ name: 'customerProfile', params: { id: oil['customer_id'] } }">
<td>{{ oil['customer_name'] }} </td>
</router-link>
<td>
<div v-if="oil['delivery_status'] == 0">Waiting</div>
<div v-else-if="oil['delivery_status'] == 1">delivered</div>
<div v-else-if="oil['delivery_status'] == 2">Out for Delivery</div>
<div v-else-if="oil['delivery_status'] == 3">Cancelled</div>
<div v-else-if="oil['delivery_status'] == 4">Partial Delivery</div>
<div v-else-if="oil['delivery_status'] == 5">Issue</div>
<div v-else-if="oil['delivery_status'] == 10">Finalized</div>
<div v-else></div>
</td>
<td>{{ oil['customer_town'] }}</td>
<td>{{ oil['customer_address'] }}</td>
<td>
<div v-if="oil['customer_asked_for_fill'] == 1">Fill</div>
<div v-else> {{ oil['gallons_ordered'] }}</div>
</td>
<td>{{ oil['expected_delivery_date'] }}</td>
<td>
<div v-if="oil['automatic'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['prime'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td>
<div v-if="oil['same_day'] == 0">No</div>
<div v-else>Yes</div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(oil['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage"
:options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryWaiting',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/waiting/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted oil order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting oil order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,342 @@
<template>
<Header />
<div v-if="user">
<div class="flex">
<div class="">
<SideBar />
</div>
<div class="w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Create a new employee</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="text-[18px] mt-10 mb-10">General Info</div>
<!-- last name -->
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Last Name</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_last_name"
class="input input-bordered w-full max-w-xs" id="title" type="text" placeholder="Last Name" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_last_name.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_last_name.$errors[0].$message }}
</span>
</div>
<!-- first name -->
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">First Name</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_first_name"
class="input input-bordered w-full max-w-xs" id="title" type="text" placeholder="First Name" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_first_name.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_first_name.$errors[0].$message }}
</span>
</div>
<!-- employee type -->
<div class="flex gap-5">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Type of employee</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="employee_type" v-model="CreateEmployeeForm.basicInfo.employee_type">
<option class="text-white" v-for="(employee, index) in employList" :key="index"
:value="employee['value']">
{{ employee['text'] }}
</option>
</select>
</div>
</div>
<div class="text-[18px] mt-10 mb-10">Employee Address</div>
<!-- street address -->
<div class="col-span-12 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Street Address</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_address" class="input input-bordered w-full max-w-xs"
id="address" type="text" placeholder="Address" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_address.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_address.$errors[0].$message }}
</span>
</div>
<!-- apt -->
<div class="col-span-12 mb-5 md:mb-5">
<input v-model="CreateEmployeeForm.basicInfo.employee_apt" class="input input-bordered w-full max-w-xs"
id="apt" type="text" placeholder="Apt, suite, unit, building, floor, etc" />
</div>
<!-- customer_town -->
<div class="col-span-12 md:col-span-4 mb-20 md:mb-5 ">
<label class="block text-white text-sm font-bold mb-2">Town</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_town" class="input input-bordered w-full max-w-xs"
id="city" type="text" placeholder="Town" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_town.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_town.$errors[0].$message }}
</span>
</div>
<!-- phone number -->
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Phone Number</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_phone_number"
class="input input-bordered w-full max-w-xs" id="phone number" type="text" placeholder="Phone Number"
@input="acceptNumber()" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_phone_number.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_phone_number.$errors[0].$message }}
</span>
</div>
<!-- state -->
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">State</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="employee_state" v-model="CreateEmployeeForm.basicInfo.employee_state">
<option class="text-white" v-for="(state, index) in stateList" :key="index" :value="state['value']">
{{ state['text'] }}
</option>
</select>
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_state.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_state.$errors[0].$message }}
</span>
</div>
<!-- zip -->
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Zip Code</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_zip" class="input input-bordered w-full max-w-xs"
id="zip" type="text" placeholder="Zip" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_zip.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_zip.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee BirthDay</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_birthday" class="input input-bordered w-full max-w-xs"
id="title" type="date" min="1945-01-01" max="2030-01-01" />
</div>
<div class="text-[18px] mt-10 mb-10">Employee Dates</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee Start Date</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_start_date"
class="input input-bordered w-full max-w-xs" id="title" type="date" min="2023-01-01" max="2030-01-01" />
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee End Date</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_end_date" class="input input-bordered w-full max-w-xs"
id="title" type="date" min="2023-01-01" max="2030-01-01" />
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Create Employee
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'EmployeeCreate',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
stateList: [],
employList: [],
employee_id: '',
CreateEmployeeForm: {
basicInfo: {
employee_last_name: "",
employee_first_name: "",
employee_town: "",
employee_address: "",
employee_apt: "",
employee_zip: "",
employee_birthday: "",
employee_phone_number: "",
employee_start_date: "",
employee_end_date: "",
employee_type: "",
employee_state: "",
},
},
}
},
validations() {
return {
CreateEmployeeForm: {
basicInfo: {
employee_last_name: {required, minLength: minLength(1)},
employee_first_name: {required, minLength: minLength(1)},
employee_town: {required, minLength: minLength(1)},
employee_type: {required},
employee_zip: {required, minLength: minLength(5)},
employee_state: {required},
employee_apt: {required},
employee_address: {required},
employee_birthday: {required},
employee_phone_number: {required},
employee_start_date: {required},
},
},
};
},
created() {
this.userStatus()
},
mounted() {
this.getEmployeeTypeList();
this.getStatesList();
},
methods: {
acceptNumber() {
let x = this.CreateEmployeeForm.basicInfo.employee_phone_number.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
if (x){
this.CreateEmployeeForm.basicInfo.employee_phone_number = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
}
else {
this.CreateEmployeeForm.basicInfo.employee_phone_number = ''
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
CreateItem(payload: {
employee_last_name: string;
employee_first_name: string;
employee_town: string;
employee_address: string;
employee_zip: string;
employee_apt: string,
employee_birthday: string;
employee_phone_number: string;
employee_start_date: string,
employee_end_date: string;
employee_type: string;
employee_state: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/employee/create";
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.employee_id= response.data['user_id']
this.$router.push({name: "employeeProfile", params: { id: this.employee_id }});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
employee_last_name: this.CreateEmployeeForm.basicInfo.employee_last_name,
employee_first_name: this.CreateEmployeeForm.basicInfo.employee_first_name,
employee_town: this.CreateEmployeeForm.basicInfo.employee_town,
employee_address: this.CreateEmployeeForm.basicInfo.employee_address,
employee_zip: this.CreateEmployeeForm.basicInfo.employee_zip,
employee_apt: this.CreateEmployeeForm.basicInfo.employee_apt,
employee_birthday: this.CreateEmployeeForm.basicInfo.employee_birthday,
employee_phone_number: this.CreateEmployeeForm.basicInfo.employee_phone_number,
employee_start_date: this.CreateEmployeeForm.basicInfo.employee_start_date,
employee_end_date: this.CreateEmployeeForm.basicInfo.employee_end_date,
employee_type: this.CreateEmployeeForm.basicInfo.employee_type,
employee_state: this.CreateEmployeeForm.basicInfo.employee_state,
};
this.CreateItem(payload);
},
getEmployeeTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/employeetype";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.employList = response.data;
})
.catch(() => {
});
},
getStatesList() {
let path = import.meta.env.VITE_BASE_URL + "/query/states";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.stateList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped></style>

379
src/pages/employee/edit.vue Normal file
View File

@@ -0,0 +1,379 @@
<template>
<Header />
<div v-if="user">
<div class="flex">
<div class="">
<SideBar />
</div>
<div class="w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Edit employee</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="text-[18px] mt-10 mb-10">General Info</div>
<!-- first name -->
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">First Name</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_first_name"
class="input input-bordered w-full max-w-xs" id="title" type="text" placeholder="First Name" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_first_name.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_first_name.$errors[0].$message }}
</span>
</div>
<!-- last name -->
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Last Name</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_last_name"
class="input input-bordered w-full max-w-xs" id="title" type="text" placeholder="Last Name" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_last_name.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_last_name.$errors[0].$message }}
</span>
</div>
<!-- employee type -->
<div class="flex gap-5">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Type of employee</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="employee_type" v-model="CreateEmployeeForm.basicInfo.employee_type">
<option class="text-white" v-for="(employee, index) in employList" :key="index"
:value="employee['value']">
{{ employee['text'] }}
</option>
</select>
</div>
</div>
<div class="text-[18px] mt-10 mb-10">Employee Address</div>
<!-- street address -->
<div class="col-span-12 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Street Address</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_address" class="input input-bordered w-full max-w-xs"
id="address" type="text" placeholder="Address" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_address.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_address.$errors[0].$message }}
</span>
</div>
<!-- apt -->
<div class="col-span-12 mb-5 md:mb-5">
<input v-model="CreateEmployeeForm.basicInfo.employee_apt" class="input input-bordered w-full max-w-xs"
id="apt" type="text" placeholder="Apt, suite, unit, building, floor, etc" />
</div>
<!-- employee_town -->
<div class="col-span-12 md:col-span-4 mb-20 md:mb-5 ">
<label class="block text-white text-sm font-bold mb-2">Town</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_town" class="input input-bordered w-full max-w-xs"
id="city" type="text" placeholder="Town" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_town.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_town.$errors[0].$message }}
</span>
</div>
<!-- phone number -->
<div class="col-span-12 md:col-span-4 mb-5 md:mb-5">
<label class="block text-white text-sm font-bold mb-2">Phone Number</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_phone_number" @input="acceptNumber()"
class="input input-bordered w-full max-w-xs" id="phone number" type="text" placeholder="Phone Number" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_phone_number.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_phone_number.$errors[0].$message }}
</span>
</div>
<!-- state -->
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">State</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="employee_state" v-model="CreateEmployeeForm.basicInfo.employee_state">
<option class="text-white" v-for="(state, index) in stateList" :key="index" defaultValue="state_default"
:value="state['value']">
{{ state['text'] }}
</option>
</select>
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_state.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_state.$errors[0].$message }}
</span>
</div>
<!-- zip -->
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<label class="block text-white text-sm font-bold mb-2">Zip Code</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_zip" class="input input-bordered w-full max-w-xs"
id="zip" type="text" placeholder="Zip" />
<span v-if="v$.CreateEmployeeForm.basicInfo.employee_zip.$error" class="text-red-600 text-center">
{{ v$.CreateEmployeeForm.basicInfo.employee_zip.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee BirthDay</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_birthday" class="input input-bordered w-full max-w-xs"
id="title" type="date" min="1945-01-01" max="2030-01-01" />
</div>
<div class="text-[18px] mt-10 mb-10">Employee Dates</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee Start Date</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_start_date"
class="input input-bordered w-full max-w-xs" id="title" type="date" min="2023-01-01" max="2030-01-01" />
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Employee End Date</label>
<input v-model="CreateEmployeeForm.basicInfo.employee_end_date" class="input input-bordered w-full max-w-xs"
id="title" type="date" min="2023-01-01" max="2030-01-01" />
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Edit Employee
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'EmployeeEdit',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
stateList: [],
employList: [],
employee_id: '',
state_default: '',
CreateEmployeeForm: {
basicInfo: {
employee_last_name: "",
employee_first_name: "",
employee_town: "",
employee_address: "",
employee_apt: "",
employee_zip: "",
employee_birthday: "",
employee_phone_number: "",
employee_start_date: "",
employee_end_date: "",
employee_type: "",
employee_state: "",
},
},
}
},
validations() {
return {
CreateEmployeeForm: {
basicInfo: {
employee_last_name: {required, minLength: minLength(1)},
employee_first_name: {required, minLength: minLength(1)},
employee_town: {required, minLength: minLength(1)},
employee_type: {required},
employee_zip: {required, minLength: minLength(5)},
employee_state: {required},
employee_apt: {required},
employee_address: {required},
employee_birthday: {required},
employee_phone_number: {required},
employee_start_date: {required},
},
},
};
},
created() {
this.userStatus()
this.getEmployee(this.$route.params.id)
},
mounted() {
this.getEmployeeTypeList();
this.getStatesList();
this.getEmployee(this.$route.params.id)
},
watch: {
$route() {
this.getEmployee(this.$route.params.id);
},
},
methods: {
acceptNumber() {
let x = this.CreateEmployeeForm.basicInfo.employee_phone_number.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
if (x){
this.CreateEmployeeForm.basicInfo.employee_phone_number = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
}
else {
this.CreateEmployeeForm.basicInfo.employee_phone_number = ''
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
EditEmployee(payload: {
employee_last_name: string;
employee_first_name: string;
employee_town: string;
employee_address: string;
employee_zip: string;
employee_apt: string,
employee_birthday: string;
employee_phone_number: string;
employee_start_date: string,
employee_end_date: string;
employee_type: string;
employee_state: string;
}) {
let path = import.meta.env.VITE_BASE_URL + "/employee/edit/" + this.employee_id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.$router.push({name: "employeeProfile", params: { id: this.employee_id }});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
getEmployee (userid:any) {
let path = import.meta.env.VITE_BASE_URL + "/employee/" + userid;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.employee_id = response.data.id
this.CreateEmployeeForm.basicInfo.employee_last_name= response.data.employee_last_name;
this.CreateEmployeeForm.basicInfo.employee_first_name= response.data.employee_first_name;
this.CreateEmployeeForm.basicInfo.employee_town= response.data.employee_town;
this.CreateEmployeeForm.basicInfo.employee_type= response.data.employee_type;
this.CreateEmployeeForm.basicInfo.employee_state= response.data.employee_state;
this.CreateEmployeeForm.basicInfo.employee_zip= response.data.employee_zip;
this.CreateEmployeeForm.basicInfo.employee_apt= response.data.employee_apt;
this.CreateEmployeeForm.basicInfo.employee_address= response.data.employee_address;
this.CreateEmployeeForm.basicInfo.employee_birthday= response.data.employee_birthday;
this.CreateEmployeeForm.basicInfo.employee_phone_number= response.data.employee_phone_number;
this.CreateEmployeeForm.basicInfo.employee_start_date= response.data.employee_start_date;
this.CreateEmployeeForm.basicInfo.employee_end_date= response.data.employee_end_date;
})
},
onSubmit() {
let payload = {
employee_last_name: this.CreateEmployeeForm.basicInfo.employee_last_name,
employee_first_name: this.CreateEmployeeForm.basicInfo.employee_first_name,
employee_town: this.CreateEmployeeForm.basicInfo.employee_town,
employee_address: this.CreateEmployeeForm.basicInfo.employee_address,
employee_zip: this.CreateEmployeeForm.basicInfo.employee_zip,
employee_apt: this.CreateEmployeeForm.basicInfo.employee_apt,
employee_birthday: this.CreateEmployeeForm.basicInfo.employee_birthday,
employee_phone_number: this.CreateEmployeeForm.basicInfo.employee_phone_number,
employee_start_date: this.CreateEmployeeForm.basicInfo.employee_start_date,
employee_end_date: this.CreateEmployeeForm.basicInfo.employee_end_date,
employee_type: this.CreateEmployeeForm.basicInfo.employee_type,
employee_state: this.CreateEmployeeForm.basicInfo.employee_state,
};
this.EditEmployee(payload);
},
getEmployeeTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/employeetype";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.employList = response.data;
})
.catch(() => {
});
},
getStatesList() {
let path = import.meta.env.VITE_BASE_URL + "/query/states";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.stateList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped></style>

163
src/pages/employee/home.vue Normal file
View File

@@ -0,0 +1,163 @@
<template>
<Header />
<div class="flex">
<div class="">
<SideBar />
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'employee' }">
employees
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
<router-link :to="{ name: 'employeeCreate' }">
<button class="btn">Create Employee</button>
</router-link>
</div>
<div class="overflow-x-auto">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Town</th>
<th>Phone Number</th>
<th></th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="person in employees" :key="person['id']">
<td>{{ person['employee_first_name'] }} {{ person['employee_last_name'] }}</td>
<td>
<div v-if="person['employee_type'] == 0">Owner</div>
<div v-else-if="person['employee_type'] == 1">Manager</div>
<div v-else-if="person['employee_type'] == 2">Secretary</div>
<div v-else-if="person['employee_type'] == 3">Office</div>
<div v-else-if="person['employee_type'] == 4">Driver</div>
<div v-else-if="person['employee_type'] == 5">Service Tech</div>
<div v-else-if="person['employee_type'] == 6">Contract</div>
<div v-else-if="person['employee_type'] == 7">Cash</div>
<div v-else-if="person['employee_type'] == 8">Driver/Tech</div>
<div v-else></div>
</td>
<td>{{ person['employee_town'] }}</td>
<td>{{ person['employee_phone_number'] }}</td>
<td class="flex gap-5">
<router-link :to="{ name: 'employeeEdit', params: { id: person['id'] } }">
<button class="btn">Edit</button>
</router-link>
<router-link :to="{ name: 'employeeProfile', params: { id: person['id'] } }">
<button class="btn">View</button>
</router-link>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage" :options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
export default defineComponent({
name: 'EmployeeHome',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
employees: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.employees = [];
this.get_employees(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_employees(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/employee/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.employees = response.data
})
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,251 @@
<template>
<Header/>
<div class="wrapper">
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
<div class=" w-full mt-10" v-if="loaded">
<div class="grid grid-cols-12 gap-5 ">
<div class="col-span-3 ">
<img src="../../../assets/images/user_placeholder.png"
alt="Drone Image"
width="200"
height="250"/>
</div>
<div class="col-span-9 bg-neutral">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex justify-end">
<div class="btn">
<router-link :to="{ name: 'employeeEdit', params: { id: employee.id } }" >
Edit Employee
</router-link>
</div>
</div>
<div class="col-span-12 font-bold flex">
{{ employee.employee_first_name }}
{{ employee.employee_last_name }}
</div>
<div class="col-span-12 font-bold flex">
{{ employee.employee_address }}
<div v-if="employee.employee_apt != 'None'">
{{ employee.employee_apt }}
</div>
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ employee.employee_town }},
</div>
<div class="pr-2">
<div v-if="employee.employee_state == '0'">Massachusetts</div>
<div v-else-if="employee.employee_state == '1'">Rhode Island</div>
<div v-else-if="employee.employee_state == '2'">New Hampshire</div>
<div v-else-if="employee.employee_state == '3'">Maine</div>
<div v-else-if="employee.employee_state == '4'">Vermont</div>
<div v-else-if="employee.employee_state == '5'">Maine</div>
<div v-else-if="employee.employee_state == '6'">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ employee.employee_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="employee.employee_apt !== 'None'">
{{ employee.employee_apt }}
</div>
<div class="col-span-12 font-bold flex">
{{ employee.employee_phone_number }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="employee.employee_type == '0'">owner</div>
<div v-else-if="employee.employee_type == '1'">manager</div>
<div v-else-if="employee.employee_type == '2'">secretary</div>
<div v-else-if="employee.employee_type == '3'">office</div>
<div v-else-if="employee.employee_type == '4'">driver</div>
<div v-else-if="employee.employee_type == '5'">tech</div>
<div v-else-if="employee.employee_type == '6'">contract</div>
<div v-else-if="employee.employee_type == '7'">cash</div>
<div v-else-if="employee.employee_type == '8'">driver/tech</div>
<div v-else>Unknown employee type</div>
</div>
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5 mt-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex text-2xl">
Delivery
</div>
<div class="col-span-6">
<div class="col-span-12 py-2">
Total Deliverys Done: 0
</div>
<div class="col-span-12 py-2">
Total Gallons Delivered: 0
</div>
<div class="col-span-12 py-2">
Total Prime: 0
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 py-2">
Total Service Calls: 0
</div>
<div class="col-span-12 py-2">
Last Service Call: 0
</div>
</div>
</div>
</div>
<div class="col-span-12 bg-neutral p-5 mt-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex text-2xl">
Service
</div>
<div class="col-span-6">
<div class="col-span-12 py-2">
Total Deliverys Done: 0
</div>
<div class="col-span-12 py-2">
Total Gallons Delivered: 0
</div>
<div class="col-span-12 py-2">
Total Prime: 0
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 py-2">
Total Service Calls: 0
</div>
<div class="col-span-12 py-2">
Last Service Call: 0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
export default defineComponent({
name: 'employeeProfile',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user_placeholder: '',
user: null,
loaded: false,
employee: {
id: '',
employee_last_name: "",
employee_first_name: "",
employee_town: "",
employee_address: "",
employee_apt: "",
employee_zip: "",
employee_birthday: "",
employee_phone_number: "",
employee_start_date: "",
employee_end_date: "",
employee_type: '',
employee_state:'',
},
}
},
created() {
this.userStatus()
},
mounted() {
this.getEmployee(this.$route.params.id)
},
watch: {
$route() {
this.getEmployee(this.$route.params.id);
},
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.getEmployee(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getEmployee (userid:any) {
let path = import.meta.env.VITE_BASE_URL + "/employee/" + userid;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
console.log(response.data)
this.employee = response.data;
this.loaded = true;
}
})
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,32 @@
import EmployeeHome from '../employee/home.vue';
import EmployeeCreate from "../employee/create.vue";
import EmployeeEdit from "../employee/edit.vue";
import EmployeeProfile from "../employee/profile/home.vue";
const employeeRoutes = [
{
path: '/employee',
name: 'employee',
component: EmployeeHome,
},
{
path: '/employee/create',
name: 'employeeCreate',
component: EmployeeCreate,
},
{
path: '/employee/edit/:id',
name: 'employeeEdit',
component: EmployeeEdit,
},
{
path: '/employee/:id',
name: 'employeeProfile',
component: EmployeeProfile,
},
]
export default employeeRoutes
//sourceMappingURL=index.ts.map

View File

@@ -0,0 +1,17 @@
<template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh">404</div>
<div class="text-h2" style="opacity: 0.4">Oops. Nothing here...</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Error404',
})
</script>

172
src/pages/pay/cancel.vue Normal file
View File

@@ -0,0 +1,172 @@
<template>
<Header />
<div class="flex">
<div class="">
<SideBar />
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
Edit Delivery
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Create Oil Delivery {{ customer_id }}
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="checkoutOil">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Order </label>
<div class=""></div>
<div class=""></div>
<div class=""></div>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Create Oil Order
</button>
</div>
</form>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'PayCancel',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
customer: null,
customer_id: null,
stripe: null,
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
},
},
mounted() {
this.getCustomer(this.$route.params.id)
this.getStripePublishableKey();
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
this.customer_id = response.datauser_id
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
checkoutOil() {
// Get Checkout Session ID
fetch('http://localhost:5001/create-checkout-session', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ book_id: book.id }),
})
.then((result) => result.json())
.then((data) => {
console.log(data);
// Redirect to Stripe Checkout
return this.stripe.redirectToCheckout({ sessionId: data.sessionId });
})
.then((res) => {
console.log(res);
});
},
getStripePublishableKey() {
fetch('http://localhost:5001/config')
.then((result) => result.json())
.then((data) => {
// Initialize Stripe.js
this.stripe = Stripe(data.publicKey);
});
},
},
})
</script>
<style scoped></style>

446
src/pages/pay/pay_oil.vue Normal file
View File

@@ -0,0 +1,446 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 mb-5">
<div class=" col-span-12 text-[24px]">
Confirm Payment Oil Delivery {{ delivery.id }}
</div>
<div class="grid grid-cols-12 bg-neutral mb-5">
<div class="col-span-12 font-bold flex pb-5 text-lg">{{ customer.account_number }}</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_address }}
<div v-if="customer.customer_apt != 'None'">
{{ customer.customer_apt }}
</div>
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
<div class="col-span-12 ">
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div class="col-span-12 py-3">
<div v-if="delivery.delivery_status == 0"> Delivery Status: Waiting</div>
<div v-else-if="delivery.delivery_status == 1">Delivery Status: delivered</div>
<div v-else-if="delivery.delivery_status == 2">Delivery Status: Out for Delivery</div>
<div v-else-if="delivery.delivery_status == 3">Delivery Status: Cancelled</div>
<div v-else-if="delivery.delivery_status == 4">Delivery Status: Partial Delivery</div>
<div v-else-if="delivery.delivery_status == 5">Delivery Status: Issue</div>
<div v-else></div>
</div>
<div class="col-span-12 py-3">Expected Delivery: {{ delivery.expected_delivery_date }}</div>
</div>
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div v-for="card in credit_cards" class="col-span-12">
<div class="flex flex-row ">
<div v-if="card.main_card" class="basis-1/3 p-2">
<div class="bg-accent rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.card_number }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex p-1 pl-4">
{{ card.security_number }}
</div>
</div>
</div>
<div v-else class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.card_number }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex p-1 pl-4">
{{ card.security_number }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div class="col-span-12 py-3">Price / Gallon: {{ delivery.customer_price }}</div>
<div class="col-span-12 py-3">
<div v-if="delivery.customer_asked_for_fill == 1"> Gallons Ordered: FILL (250)</div>
<div v-else> Gallons Ordered: {{ delivery.gallons_ordered }}</div>
</div>
<div class="col-span-12 py-3" v-if="delivery.prime == 1">
Prime Fee: {{ delivery.prime }}
</div>
<div class="col-span-12 py-3" v-if="delivery.same_day == 1">
Same Day: {{ delivery.same_day }}
</div>
<div class="col-span-12 font-bold py-5 text-lg">Total: {{ delivery.total_price }}</div>
</div>
</div>
<div class="flex justify-between">
<!-- <button class="btn" @click="checkoutOilCreditStripe()">-->
<!-- Pay Credit Card (Stripe)-->
<!-- </button>-->
<button class="btn" @click="checkoutOilUpdatePayment(0)">
Cash Payment
</button>
<button class="btn" @click="checkoutOilUpdatePayment(1)">
Pay Credit Terminal
</button>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'PayOil',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
user_id: 0,
},
delivery: {
id: 0,
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: 0,
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: 0,
customer_price: 0,
customer_temperature: 0,
dispatcher_notes: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: 0,
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
pre_charge_amount: 0,
total_price: 0,
},
credit_cards: [
{
id: 0,
name_on_card: '',
main_card: false,
card_number: '',
expiration_month: '',
type_of_card: '',
last_four_digits: '',
expiration_year: '',
security_number: 0,
}
],
stripe: null,
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_address: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
account_number: '',
},
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
},
},
mounted() {
this.getOilOrder(this.$route.params.id)
// this.getStripePublishableKey();
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
},
getOilOrder(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/order/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.delivery = response.data;
this.getCustomer(this.delivery.customer_id)
this.getCreditCards(this.delivery.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get oil order",
type: "error",
});
});
},
getCreditCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/' + user_id;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.credit_cards = response.data
})
},
getCustomer(userid: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.customer = response.data
})
},
checkoutOilUpdateCreditStripe() {
let path = import.meta.env.VITE_BASE_URL + "/delivery/cash/" + this.delivery.id + '/2';
axios({
method: "PUT",
url: path,
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "marked payment as STRIPE credit card",
type: "error",
});
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not update with credit card",
type: "error",
});
});
},
checkoutOilUpdatePayment(payment_type: number) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/cash/" + this.delivery.id + '/' + payment_type;
axios({
method: "PUT",
url: path,
})
.then((response: any) => {
if (response.data.ok) {
if (payment_type == 1) {
notify({
title: "Success",
text: "marked payment as credit (bank terminal)",
type: "success",
});
}
if (payment_type == 0) {
notify({
title: "Success",
text: "marked payment as cash (COD)",
type: "success",
});
}
this.$router.push({name: "customerProfile", params: {id: this.customer.id}});
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not update wth cash",
type: "error",
});
});
},
// checkoutOilCreditStripe() {
//
// let path = import.meta.env.VITE_PAY_URL + "/pay/charge";
// axios({
// method: "get",
// url: path,
// })
// .then((response: any) => {
// this.checkoutOilUpdateCreditStripe();
// // Redirect to Stripe Checkout
// return this.stripe.redirectToCheckout({sessionId: response.data.sessionId});
// })
// .catch(() => {
// notify({
// title: "Error",
// text: "Could not find customer",
// type: "error",
// });
// });
// },
// getStripePublishableKey() {
// let path = import.meta.env.VITE_PAY_URL + "/pay/config";
// axios({
// method: "get",
// url: path,
// })
// .then((response: any) => {
// this.stripe = Stripe(response.data.publicKey);
// })
// .catch(() => {
// notify({
// title: "Error",
// text: "Could not find customer",
// type: "error",
// });
// });
// },
//
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,484 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 mb-5">
<div class=" col-span-12 text-[24px]">
Confirm Payment Service Call {{ service_id }}
</div>
<div class="grid grid-cols-12 bg-neutral mb-5">
<div class="col-span-12 font-bold flex pb-5 text-lg">{{ customer.account_number }}</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_address }}
<div v-if="customer.customer_apt != 'None'">
{{ customer.customer_apt }}
</div>
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
<div class="col-span-12 ">
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div class="col-span-12 py-3">
<div v-if="service.service_type == '0'">Service Type: General</div>
<div v-else-if="service.service_type == '1'">Service Type: Cleaning / Tuneup</div>
<div v-else-if="service.service_type == '2'">Service Type: No Heat</div>
<div v-else-if="service.service_type == '3'">Service Type: Install</div>
<div v-else-if="service.service_type == '4'">Service Type: Call Back</div>
<div v-else-if="service.service_type == '5'">Service Type: Quote</div>
<div v-else-if="service.service_type == '6'">Service Type: Emergency</div>
<div v-else></div>
</div>
<div class="col-span-12 py-3">Tech: {{ service.tech_first_name }} {{ service.tech_last_name }}</div>
<div class="col-span-12 py-3">Expected Service Date: {{ service.scheduled_date }}</div>
</div>
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div v-for="card in credit_cards" class="col-span-12">
<div class="flex flex-row ">
<div v-if="card.main_card" class="basis-1/3 p-2">
<div class="bg-accent rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.card_number }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex p-1 pl-4">
{{ card.security_number }}
</div>
</div>
</div>
<div v-else class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ card.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.name_on_card }}
</div>
<div class="flex p-1 pl-4">
{{ card.card_number }}
</div>
<div class="flex p-1 pl-4">
{{ card.expiration_month }}/ {{ card.expiration_year }}
</div>
<div class="flex p-1 pl-4">
{{ card.security_number }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-12 mb-5 bg-neutral">
<div class="col-span-12 py-3">Price / hour: {{ service_prices.price_service_hour }}</div>
<div class="col-span-12 py-3" v-if="service.payment_type == 0">Pay Method: Cash (COD)</div>
<div class="col-span-12 py-3" v-if="service.payment_type == 1">Pay Method: Credit Card</div>
<div class="col-span-12 py-3" v-if="service.payment_type == 2">Pay Method: Stripe</div>
<div class="col-span-12 py-3" v-if="service.payment_type == 2">Pay Method: Cash/Credit Mix</div>
<div class="col-span-12 font-bold py-5 text-lg">Pre-Charge: 300$</div>
</div>
</div>
<div class="flex justify-between">
<!-- <button class="btn" @click="checkoutServiceCreditStripe()">-->
<!-- Pay Credit Card (Stripe)-->
<!-- </button>-->
<button class="btn" @click="checkoutServiceUpdatePayment(0)">
Cash Payment
</button>
<button class="btn" @click="checkoutServiceUpdatePayment(1)">
Pay Credit Terminal
</button>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'PayOil',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
user_id: 0,
},
service_id: null,
service: {
id: 0,
customer_id: 0,
customer_last_name: '',
customer_first_name: '',
customer_town: '',
customer_state: '',
customer_zip: '',
customer_apt: '',
customer_address: '',
status: 0,
service_type: '',
when_called: '',
scheduled_date: '',
scheduled_time: '',
when_serviced: '',
completed: 0,
tech_id: 0,
tech_first_name: '',
tech_last_name: '',
payment_type: 0,
payment_card_id: 0,
},
service_notes: {
service_call_id: 0,
dispatcher_notes: '',
dispatcher_subject: '',
time_added: '',
dispatcher_id: 0,
dispatcher_name: '',
},
service_prices: {
id: 0,
price_service_hour: 0,
price_emergency_service_hour: 0,
price_emergency_call: 0,
price_out_of_oil: 0,
price_prime: 0,
price_same_day: 0,
price_cleaning: 0,
date: '',
},
credit_cards: [
{
id: 0,
name_on_card: '',
main_card: false,
card_number: '',
expiration_month: '',
type_of_card: '',
last_four_digits: '',
expiration_year: '',
security_number: 0,
}
],
stripe: null,
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_address: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
account_number: '',
},
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
},
},
};
},
created() {
this.userStatus();
this.getServiceOrder(this.$route.params.id);
},
watch: {
$route() {
},
},
mounted() {
this.getServicePrices();
// this.getStripePublishableKey();
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
},
getServiceOrder(service_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/" + service_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.service = response.data;
this.getCustomer(this.service.customer_id)
this.getCreditCards(this.service.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get service order",
type: "error",
});
});
},
getServicePrices() {
let path = import.meta.env.VITE_BASE_URL + "/admin/service/get";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.service_prices = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not get service order",
type: "error",
});
});
},
getServiceOrderNotes(service_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/call/notes" + service_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.service = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not get service order",
type: "error",
});
});
},
getCreditCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/' + user_id;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.credit_cards = response.data
})
},
getCustomer(userid: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.customer = response.data
})
},
checkoutServiceUpdateCreditStripe() {
let path = import.meta.env.VITE_BASE_URL + "/service/cash/" + this.service.id + '/2';
axios({
method: "PUT",
url: path,
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "marked payment as STRIPE credit card",
type: "success",
});
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not update with credit card Stripe",
type: "error",
});
});
},
checkoutServiceUpdatePayment(payment_type: number) {
let path = import.meta.env.VITE_BASE_URL + "/service/paymenttype/" + this.service.id + '/' + payment_type;
axios({
method: "PUT",
url: path,
})
.then((response: any) => {
if (response.data.ok) {
if (payment_type == 1) {
notify({
title: "Success",
text: "marked payment as credit (bank terminal)",
type: "success",
});
}
if (payment_type == 0) {
notify({
title: "Success",
text: "marked payment as cash (COD)",
type: "success",
});
}
this.$router.push({name: "customerProfile", params: {id: this.customer.id}});
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not update wth cash",
type: "error",
});
});
},
// checkoutServiceCreditStripe() {
//
// let path = import.meta.env.VITE_PAY_URL + "/pay/charge";
// axios({
// method: "get",
// url: path,
// })
// .then((response: any) => {
// this.checkoutServiceUpdateCreditStripe();
// // Redirect to Stripe Checkout
// return this.stripe.redirectToCheckout({sessionId: response.data.sessionId});
// })
// .catch(() => {
// notify({
// title: "Error",
// text: "Could not find customer",
// type: "error",
// });
// });
// },
//
// getStripePublishableKey() {
// let path = import.meta.env.VITE_PAY_URL + "/pay/config";
// axios({
// method: "get",
// url: path,
// })
// .then((response: any) => {
// this.stripe = Stripe(response.data.publicKey);
// })
//
// },
},
})
</script>
<style scoped></style>

33
src/pages/pay/routes.ts Normal file
View File

@@ -0,0 +1,33 @@
import PayOil from '../pay/pay_oil.vue';
import PayService from "../pay/pay_service.vue";
import PaySuccess from "../pay/success.vue";
import PayCancel from "../pay/cancel.vue";
const payRoutes = [
{
path: '/pay/service/:id',
name: 'payService',
component: PayService,
},
{
path: '/pay/oil/:id',
name: 'payOil',
component: PayOil,
},
{
path: '/pay/success',
name: 'paySuccess',
component: PaySuccess,
},
{
path: '/pay/cancel',
name: 'payCancel',
component: PayCancel,
},
]
export default payRoutes
//sourceMappingURL=index.ts.map

176
src/pages/pay/success.vue Normal file
View File

@@ -0,0 +1,176 @@
<template>
<Header />
<div class="flex">
<div class="">
<SideBar />
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil['id'] } }">
Edit Delivery
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Create Oil Delivery {{ customer_id }}
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="checkoutOil">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Order </label>
<div class=""></div>
<div class=""></div>
<div class=""></div>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Create Oil Order
</button>
</div>
</form>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'PaySuccess',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: null,
customer: null,
customer_id: null,
stripe: null,
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {required, minLength: minLength(1)},
expected_delivery_date: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
},
},
mounted() {
this.getCustomer(this.$route.params.id)
this.getStripePublishableKey();
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
this.customer_id = response.data.user_id;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
checkoutOil() {
// Get Checkout Session ID
fetch('http://localhost:5001/create-checkout-session', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ book_id: book.id }),
})
.then((result) => result.json())
.then((data) => {
console.log(data);
// Redirect to Stripe Checkout
return this.stripe.redirectToCheckout({ sessionId: data.sessionId });
})
.then((res) => {
console.log(res);
});
},
getStripePublishableKey() {
fetch('http://localhost:5001/config')
.then((result) => result.json())
.then((data) => {
// Initialize Stripe.js
this.stripe = Stripe(data.publicKey);
});
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,400 @@
<template>
<Header />
<div class="flex">
<div class="">
<SideBar />
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="grid grid-cols-12">
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex pb-5 text-lg">{{customer.account_number}}</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Service Category</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="customer_state" v-model="CreateServiceOrderForm.basicInfo.type_of_service">
<option class="text-white" v-for="(cat, index) in serviceList" :key="index" :value="cat['value']">
{{ cat['text'] }}
</option>
</select>
<span v-if="v$.CreateServiceOrderForm.basicInfo.type_of_service.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.type_of_service.$errors[0].$message }}
</span>
</div>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Subject</span>
</div>
<input type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs"
v-model="CreateServiceOrderForm.basicInfo.dispatcher_subject_taken" />
</label>
<span v-if="v$.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken.$error"
class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="form-control">
<div class="label">
<span class="label-text">What is the issue</span>
</div>
<textarea class="textarea textarea-bordered h-24" placeholder="Describe the issue for the service tech .."
v-model="CreateServiceOrderForm.basicInfo.dispatcher_notes_taken"></textarea>
</label>
<span v-if="v$.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken.$error"
class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expected Service Date </label>
<input v-model="CreateServiceOrderForm.basicInfo.date_scheduled" class="input input-bordered w-full max-w-xs"
id="title" type="date" min="2023-01-01" max="2030-01-01" />
<span v-if="v$.CreateServiceOrderForm.basicInfo.date_scheduled.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.date_scheduled.$errors[0].$message }}
</span>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Service Tech</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example" id="customer_state"
v-model="CreateServiceOrderForm.basicInfo.service_tech">
<option class="text-white" v-for="(tech, index) in serviceTechsList" :key="index" :value="tech['id']">
{{ tech['employee_last_name'] }}
</option>
</select>
<span v-if="v$.CreateServiceOrderForm.basicInfo.service_tech.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.service_tech.$errors[0].$message }}
</span>
</div>
<div class="bg-neutral">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Cash</label>
<input v-model="CreateServiceOrderForm.basicInfo.cash"
class="checkbox"
id="cash"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Credit </label>
<input v-model="CreateServiceOrderForm.basicInfo.credit"
class="checkbox"
id="Credit"
type="checkbox"/>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Cards Payment</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="userCards"
v-model="CreateServiceOrderForm.basicInfo.userCards">
<option class="text-white" v-for="(card, index) in userCards"
:key="index"
:value="card['id']">
{{ card['type_of_card'] }} {{ card['card_number'] }}
</option>
</select>
</div>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Create Service Call
</button>
</div>
</form>
</div>
</div>
</div>
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'ServiceCreate',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: 0,
user_id: 0,
},
serviceList: [],
serviceTechsList: [],
userCards: [],
service_id: 0,
CreateServiceOrderForm: {
basicInfo: {
type_of_service: '',
dispatcher_notes_taken: '',
dispatcher_subject_taken: '',
date_scheduled: '',
service_tech: '',
userCards: [],
credit: false,
cash: false,
credit_card_id: 0,
},
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
account_number: '',
},
}
},
validations() {
return {
CreateServiceOrderForm: {
basicInfo: {
type_of_service: {required},
dispatcher_notes_taken: {required, minLength: minLength(10)},
dispatcher_subject_taken: {required, minLength: minLength(10)},
date_scheduled: {required},
service_tech: {required},
},
},
};
},
created() {
this.userStatus()
this.getServiceTypeList()
this.getServiceTechsList()
},
watch: {
$route() {
this.getCustomer(this.$route.params.id);
this.getPaymentCards(this.$route.params.id);
},
},
mounted() {
this.getCustomer(this.$route.params.id)
this.getPaymentCards(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
console.log(this.customer)
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/"+ user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
})
.catch(() => {
});
},
CreateServiceOrder(payload: {
dispatcher_notes_taken: string,
dispatcher_subject_taken: string,
date_scheduled: string,
type_of_service: string,
dispatcher_id: number,
cash: boolean,
credit: boolean,
credit_card_id: any,
}) {
let path = import.meta.env.VITE_BASE_URL + "/service/create/" + this.customer.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.service_id = response.data.service_id
this.$router.push({name: "payService", params: { id: this.service_id }});
}
if (response.data.error) {
}
})
},
onSubmit() {
let payload = {
dispatcher_notes_taken: this.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken,
dispatcher_subject_taken: this.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken,
date_scheduled: this.CreateServiceOrderForm.basicInfo.date_scheduled,
type_of_service: this.CreateServiceOrderForm.basicInfo.type_of_service,
dispatcher_id: this.user.user_id,
cash: this.CreateServiceOrderForm.basicInfo.cash,
credit: this.CreateServiceOrderForm.basicInfo.credit,
credit_card_id: this.CreateServiceOrderForm.basicInfo.userCards,
};
this.CreateServiceOrder(payload);
},
getServiceTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/servicetype";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.serviceList = response.data;
})
.catch(() => {});
},
getServiceTechsList() {
let path = import.meta.env.VITE_BASE_URL + "/employee/techs";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.serviceTechsList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped></style>

501
src/pages/service/edit.vue Normal file
View File

@@ -0,0 +1,501 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'customer' }">
Customers
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md p-6 ">
<div class="text-[24px]">Edit Service Call
</div>
<div class="grid grid-cols-12">
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex">
{{ customer.customer_first_name }}
{{ customer.customer_last_name }}
</div>
<div class="col-span-12
font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Maine</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<form class="rounded-md px-8 pt-6 pb-8 mb-4 w-full" enctype="multipart/form-data" @submit.prevent="onSubmit">
<div class="bg-neutral">
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Cash</label>
<input v-model="CreateServiceOrderForm.basicInfo.cash"
class="checkbox"
id="cash"
type="checkbox"/>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0 gap-10">
<label class="block text-white text-sm font-bold cursor-pointer label">Credit </label>
<input v-model="CreateServiceOrderForm.basicInfo.card"
class="checkbox"
id="Credit"
type="checkbox"/>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Customer Cards Payment</label>
<select
class="select select-bordered w-full max-w-xs"
aria-label="Default select example" id="userCards"
v-model="CreateServiceOrderForm.basicInfo.userCards">
<option class="text-white" v-for="(card, index) in userCards"
:key="index"
:value="card['id']">
{{ card['type_of_card'] }} {{ card['card_number'] }}
</option>
</select>
</div>
</div>
<div class="col-span-12 md:col-span-4 mb-5 md:mb-0">
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Service Category</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="customer_state" v-model="CreateServiceOrderForm.basicInfo.type_of_service">
<option class="text-white" v-for="(cat, index) in serviceList" :key="index" :value="cat['value']">
{{ cat['text'] }}
</option>
</select>
<span v-if="v$.CreateServiceOrderForm.basicInfo.type_of_service.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.type_of_service.$errors[0].$message }}
</span>
</div>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Subject</span>
</div>
<input type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs"
v-model="CreateServiceOrderForm.basicInfo.dispatcher_subject_taken"/>
</label>
<span v-if="v$.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken.$error"
class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="form-control">
<div class="label">
<span class="label-text">What is the issue</span>
</div>
<textarea class="textarea textarea-bordered h-24" placeholder="Describe the issue for the service tech .."
v-model="CreateServiceOrderForm.basicInfo.dispatcher_notes_taken"></textarea>
</label>
<span v-if="v$.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken.$error"
class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken.$errors[0].$message }}
</span>
</div>
<div class="mb-4">
<label class="block text-white text-sm font-bold mb-2">Expected Service Date </label>
<input v-model="CreateServiceOrderForm.basicInfo.date_scheduled"
class="input input-bordered w-full max-w-xs"
id="title" type="date" min="2023-01-01" max="2030-01-01"/>
<span v-if="v$.CreateServiceOrderForm.basicInfo.date_scheduled.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.date_scheduled.$errors[0].$message }}
</span>
</div>
<div class="flex-1 mb-4">
<label class="block text-white text-sm font-bold mb-2">Service Tech</label>
<select class="select select-bordered w-full max-w-xs" aria-label="Default select example"
id="customer_state"
v-model="CreateServiceOrderForm.basicInfo.service_tech_id">
<option class="text-white" v-for="(tech, index) in serviceTechsList" :key="index" :value="tech['id']">
{{ tech['employee_last_name'] }}
</option>
</select>
<span v-if="v$.CreateServiceOrderForm.basicInfo.service_tech_id.$error" class="text-red-600 text-center">
{{ v$.CreateServiceOrderForm.basicInfo.type_of_service.$errors[0].$message }}
</span>
</div>
<div class="col-span-12 md:col-span-12 flex mt-5 mb-5">
<button class="btn">
Edit Service Call
</button>
</div>
</form>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'ServiceEdit',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: 0
},
serviceList: [],
serviceTechsList: [],
userCards: [],
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
serviceCall: {
id: 0,
tech_id: 0,
customer_id: 0,
type_of_service: 0,
dispatcher_notes_taken: '',
dispatcher_subject_taken: '',
date_scheduled: '',
payment_type: 0,
payment_card_id: 0,
same_day: 0,
},
CreateServiceOrderForm: {
basicInfo: {
type_of_service: '',
dispatcher_notes_taken: '',
dispatcher_subject_taken: '',
date_scheduled: '',
service_tech_id: '',
userCards: [],
credit_card_id: 0,
cash: false,
card: false,
},
},
}
},
validations() {
return {
CreateServiceOrderForm: {
basicInfo: {
type_of_service: {required},
dispatcher_notes_taken: {required, minLength: minLength(10)},
dispatcher_subject_taken: {required, minLength: minLength(10)},
date_scheduled: {required},
service_tech_id: {required},
},
},
};
},
created() {
this.userStatus()
this.getServiceTypeList()
this.getServiceTechsList()
},
watch: {
$route() {
this.getServiceCall(this.$route.params.id);
this.getServiceCallNotes(this.$route.params.id)
},
},
mounted() {
this.getServiceCall(this.$route.params.id)
this.getServiceCallNotes(this.$route.params.id)
this.getServiceTechsList()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
this.getPaymentCards(this.serviceCall.customer_id);
if (this.serviceCall.payment_type == 1) {
this.getPaymentCard(this.serviceCall.payment_card_id)
}
if (this.serviceCall.payment_type == 2) {
this.getPaymentCard(this.serviceCall.payment_card_id)
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCard = response.data;
this.CreateServiceOrderForm.basicInfo.userCards = response.data.id
})
.catch(() => {
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
})
.catch(() => {
});
},
// gets the item from paramater router
getServiceCall(serviceid: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/" + serviceid;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.CreateServiceOrderForm.basicInfo.type_of_service = response.data.service_type;
this.CreateServiceOrderForm.basicInfo.date_scheduled = response.data.scheduled_date;
this.CreateServiceOrderForm.basicInfo.service_tech_id = response.data.tech_id;
this.CreateServiceOrderForm.basicInfo.date_scheduled = response.data.scheduled_date;
this.serviceCall = response.data
if (response.data.payment_type == 0) {
this.CreateServiceOrderForm.basicInfo.card = false
this.CreateServiceOrderForm.basicInfo.cash = true
}
if (response.data.payment_type == 1) {
this.CreateServiceOrderForm.basicInfo.card = true
this.CreateServiceOrderForm.basicInfo.cash = false
}
if (response.data.payment_type == 2) {
this.CreateServiceOrderForm.basicInfo.card = true
this.CreateServiceOrderForm.basicInfo.cash = true
}
this.getCustomer(this.serviceCall.customer_id);
}
})
},
getServiceCallNotes(serviceid: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/call/notes/" + serviceid;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken = response.data.dispatcher_notes;
this.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken = response.data.dispatcher_subject;
}
})
},
EditServiceOrder(payload: {
dispatcher_notes_taken: string;
dispatcher_subject_taken: string;
date_scheduled: string;
type_of_service: string,
tech_id: number,
cash: boolean,
credit: boolean,
credit_card_id: any,
}) {
let path = import.meta.env.VITE_BASE_URL + "/service/edit/" + this.serviceCall.id;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.$router.push({name: "serviceCall", params: { id: this.serviceCall.id }});
}
if (response.data.error) {
this.$router.push("/");
}
})
},
onSubmit() {
let payload = {
dispatcher_notes_taken: this.CreateServiceOrderForm.basicInfo.dispatcher_notes_taken,
dispatcher_subject_taken: this.CreateServiceOrderForm.basicInfo.dispatcher_subject_taken,
date_scheduled: this.CreateServiceOrderForm.basicInfo.date_scheduled,
type_of_service: this.CreateServiceOrderForm.basicInfo.type_of_service,
tech_id: this.serviceCall.tech_id,
cash: this.CreateServiceOrderForm.basicInfo.cash,
credit: this.CreateServiceOrderForm.basicInfo.card,
credit_card_id: this.CreateServiceOrderForm.basicInfo.userCards,
};
this.EditServiceOrder(payload);
},
getServiceTypeList() {
let path = import.meta.env.VITE_BASE_URL + "/query/servicetype";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.serviceList = response.data;
})
.catch(() => {
});
},
getServiceTechsList() {
let path = import.meta.env.VITE_BASE_URL + "/employee/techs";
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.serviceTechsList = response.data;
})
.catch(() => {
});
},
},
})
</script>
<style scoped></style>

216
src/pages/service/home.vue Normal file
View File

@@ -0,0 +1,216 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
</ul>
</div>
<div class="flex justify-end">
</div>
<div class="overflow-x-auto">
<div class="flex start">Service Calls</div>
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Customer Name</th>
<th>Scheduled Date</th>
<th>Status</th>
<th>Town</th>
<th>Service Type</th>
<th>Initial Call</th>
<th>Tech Name</th>
<th>Payment Type</th>
</tr>
</thead>
<tbody>
<!-- row 1 -->
<tr v-for="service in service_calls" :key="service['id']">
<td>
<router-link :to="{ name: 'customerProfile', params: { id: person['id'] } }">
{{ person['customer_first_name'] }} {{ person['customer_last_name'] }}
</router-link>
</td>
<td>
{{ service['scheduled_date'] }}
</td>
<td>
<div v-if="service['status'] == 0">Waiting/not paid</div>
<div v-else-if="service['status'] == 1">Paid /waiting</div>
<div v-else-if="service['status'] == 2">Scheduled Today</div>
<div v-else-if="service['status'] == 3">Completed/Unpaid</div>
<div v-else-if="service['status'] == 4">Completed/Paid</div>
<div v-else></div>
</td>
<td>
{{ service['customer_town'] }}
</td>
<td>
<div v-if="service['service_type'] == 0">General</div>
<div v-else-if="service['service_type'] == 1">Cleaning / Tuneup</div>
<div v-else-if="service['service_type'] == 2">No Heat</div>
<div v-else-if="service['service_type'] == 3">Install</div>
<div v-else-if="service['service_type'] == 4">Call Back</div>
<div v-else-if="service['service_type'] == 5">Quote</div>
<div v-else-if="service['service_type'] == 6" class="text-red-700 font-bold">Emergency</div>
<div v-else></div>
</td>
<td>
{{ service['when_called'] }}
</td>
<td>
{{ service['tech_first_name'] }} {{ service['tech_last_name'] }}
</td>
<td>
<div v-if="service['payment_type'] == 0">Cash C.O.D</div>
<div v-else-if="service['payment_type'] == 1">Credit</div>
<div v-else-if="service['payment_type'] == 2">Stripe</div>
<div v-else-if="service['payment_type'] == 3">Cash/Credit</div>
<div v-else></div>
</td>
<td class="flex gap-5">
<router-link :to="{ name: 'serviceCall', params: { id: service['id'] } }">
<button class="btn">View</button>
</router-link>
<router-link :to="{ name: 'serviceEdit', params: { id: service['id'] } }">
<button class="btn">Edit</button>
</router-link>
<button @click.prevent="deleteCall(service['id'])" class="btn">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="flex justify-center" v-if="recordsLength > 9">
<pagination @paginate="getPage" :records="recordsLength" v-model="page" :per-page="perPage" :options="options">
</pagination>
<div class="flex justify-center mb-10"> {{ recordsLength }} items Found</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'ServiceCall',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
service_calls: [],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.service_calls = [];
this.get_service_call(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_service_call(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/service/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.service_calls = response.data
})
},
deleteCall(service_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/service/delete/' + service_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted service order",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting service order",
type: "success",
});
}
})
},
},
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,32 @@
import ServiceHome from '../service/home.vue';
import ServiceCreate from '../service/create.vue';
import ServiceEdit from '../service/edit.vue';
import ServiceCall from '../service/view.vue';
const serviceRoutes = [
{
path: '/service',
name: 'service',
component: ServiceHome,
},
{
path: '/service/:id',
name: 'serviceCall',
component: ServiceCall,
},
{
path: '/service/create/:id',
name: 'serviceCreate',
component: ServiceCreate,
},
{
path: '/service/edit/:id',
name: 'serviceEdit',
component: ServiceEdit,
},
]
export default serviceRoutes
//sourceMappingURL=index.ts.map

423
src/pages/service/view.vue Normal file
View File

@@ -0,0 +1,423 @@
<template>
<Header/>
<div class="flex">
<div class="">
<SideBar/>
</div>
<div class=" w-full px-10">
<div class="text-sm breadcrumbs">
<ul>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
<router-link :to="{ name: 'service' }">
Service Home
</router-link>
</li>
</ul>
</div>
<div class="grid grid-cols-1 rounded-md pb-5">
<div class="text-[24px]">
View Service Call # {{ serviceCall.id }}
</div>
<div class="grid grid-cols-12">
<div class="col-span-6">
<div class="col-span-12 font-bold">
Customer
</div>
<div class="col-span-6 bg-neutral p-5">
<div class="grid grid-cols-12">
<div class="col-span-12 font-bold flex">
{{ serviceCall.customer_first_name }}
{{ serviceCall.customer_last_name }}
</div>
<div class="col-span-12 font-bold flex">
<div class="pr-2">
{{ customer.customer_town }},
</div>
<div class="pr-2">
<div v-if="customer.customer_state == 0">Massachusetts</div>
<div v-else-if="customer.customer_state == 1">Rhode Island</div>
<div v-else-if="customer.customer_state == 2">New Hampshire</div>
<div v-else-if="customer.customer_state == 3">Maine</div>
<div v-else-if="customer.customer_state == 4">Vermont</div>
<div v-else-if="customer.customer_state == 5">Connecticut</div>
<div v-else-if="customer.customer_state == 6">New York</div>
<div v-else>Unknown state</div>
</div>
<div class="pr-2">
{{ customer.customer_zip }}
</div>
</div>
<div class="col-span-12 font-bold flex" v-if="customer.customer_apt !== 'None'">
{{ customer.customer_apt }}
</div>
<div class="col-span-12 font-bold flex">
<div v-if="customer.customer_home_type == 0">Residential</div>
<div v-else-if="customer.customer_home_type == 1">apartment</div>
<div v-else-if="customer.customer_home_type == 2">condo</div>
<div v-else-if="customer.customer_home_type == 3">commercial</div>
<div v-else-if="customer.customer_home_type == 4">business</div>
<div v-else-if="customer.customer_home_type == 5">construction</div>
<div v-else-if="customer.customer_home_type == 6">container</div>
</div>
<div class="col-span-12 font-bold flex">
{{ customer.customer_phone_number }}
</div>
</div>
</div>
</div>
<div class="col-span-6 ">
<div class="flex justify-end" v-if="serviceCall.id ">
<router-link :to="{ name: 'serviceEdit', params: { id: serviceCall.id } }">
<button class="btn">Edit Service Call</button>
</router-link>
</div>
</div>
</div>
</div>
<div class="col-span-6">
<div class="col-span-12 font-bold">
Service Status
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
Service Category
</div>
<div class="col-span-12">
<div v-if="serviceCall.service_type == 0">General</div>
<div v-else-if="serviceCall.service_type == 1">Cleaning / Tuneup</div>
<div v-else-if="serviceCall.service_type == 2">No Heat</div>
<div v-else-if="serviceCall.service_type == 3">Install</div>
<div v-else-if="serviceCall.service_type == 4">Call Back</div>
<div v-else-if="serviceCall.service_type == 5">Quote</div>
<div v-else-if="serviceCall.service_type == 6">Emergency</div>
<div v-else></div>
</div>
<div class="col-span-12 font-bold mt-10">
Scheduled date/time
</div>
<div class="col-span-12 ">
{{ serviceCall.scheduled_date }}
</div>
<div class="col-span-12 font-bold mt-10">
Tech Name
</div>
<div class="col-span-12 ">
{{ serviceCall.tech_first_name }} {{ serviceCall.tech_last_name }}
</div>
<div class="col-span-12 font-bold mt-10">
When Called
</div>
<div class="col-span-12 ">
{{ serviceCall.when_called }}
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Dispatcher Notes
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
Subject
</div>
<div class="col-span-12">
{{ serviceCallNotes.dispatcher_subject }}
</div>
<div class="col-span-12 font-bold mt-10">
Notes
</div>
<div class="col-span-12 ">
{{ serviceCallNotes.dispatcher_notes }}
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Amount
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="serviceCall.customer_asked_for_fill==1">Fill</div>
<div v-else>{{ serviceCall.gallons_ordered }}</div>
</div>
</div>
</div>
<div class="col-span-6 mt-5">
<div class="col-span-12 font-bold">
Payment
</div>
<div class="grid grid-cols-12 bg-neutral p-5">
<div class="col-span-12 font-bold">
<div v-if="serviceCall.payment_type==0">Cash</div>
<div v-else-if="serviceCall.payment_type==1">Credit Card</div>
<div v-else-if="serviceCall.payment_type==2">Credit Card & cash</div>
<div v-else>No Payment Type Added</div>
</div>
<div class="col-span-12" v-if="serviceCall.payment_type==1">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
<div class="col-span-12" v-if="serviceCall.payment_type==2">
<div class="flex">
<div class="basis-1/3 p-2">
<div class="bg-neutral rounded-md border-2 ">
<div class="flex p-3">
{{ userCard.type_of_card }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.name_on_card }}
</div>
<div class="flex p-1 pl-4">
****-****-****-{{ userCard.last_four_digits }}
</div>
<div class="flex p-1 pl-4">
{{ userCard.expiration_month }}/ {{ userCard.expiration_year }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import {notify} from "@kyvg/vue3-notification"
import {minLength, required} from "@vuelidate/validators";
export default defineComponent({
name: 'serviceCall',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
user: {
id: 0
},
serviceTech: [],
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
serviceCallNotes: {
service_call_id: '',
dispatcher_notes: '',
dispatcher_subject: '',
time_added: '',
dispatcher_id: '',
dispatcher_name: '',
},
serviceCall: {
id: 0,
customer_id: 0,
customer_last_name: '',
customer_first_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_address: '',
status: 0,
service_type: 0,
when_called: '',
scheduled_date: '',
scheduled_time: '',
when_serviced: '',
completed: 0,
tech_id: 0,
tech_first_name: '',
tech_last_name: '',
payment_type: 0,
payment_card_id: 0,
},
}
},
validations() {
return {
CreateServiceOrderForm: {
basicInfo: {
type_of_service: {required},
dispatcher_notes_taken: {required, minLength: minLength(10)},
dispatcher_subject_taken: {required, minLength: minLength(10)},
date_scheduled: {required},
service_tech_id: {required},
},
},
};
},
created() {
this.userStatus()
},
watch: {
$route() {
this.getServiceCall(this.$route.params.id);
this.getServiceCallNotes(this.$route.params.id);
},
},
mounted() {
this.getServiceCall(this.$route.params.id);
this.getServiceCallNotes(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getCustomer(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customer = response.data;
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCard = response.data;
})
.catch(() => {
});
},
getServiceCall(service_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/call/" + service_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.serviceCall = response.data
this.getCustomer(this.serviceCall.customer_id)
if (this.serviceCall.payment_type != null) {
this.getPaymentCard(this.serviceCall.payment_card_id);
}
}
})
},
getServiceCallNotes(service_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/service/call/notes/" + service_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.serviceCallNotes = response.data
}
})
},
},
})
</script>
<style scoped></style>

2
src/router/index.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const router: import("vue-router").Router;
export default router;

42
src/router/index.ts Normal file
View File

@@ -0,0 +1,42 @@
import { createRouter, createWebHistory } from "vue-router";
import authRoutes from '../pages/auth/routes.ts';
import oilRoutes from '../pages/delivery/routes.ts';
import serviceRoutes from '../pages/service/routes.ts';
import employeeRoutes from '../pages/employee/routes.ts';
import payRoutes from '../pages/pay/routes.ts';
import customerRoutes from '../pages/customer/routes.ts';
import Home from '../pages/Index.vue';
import cardRoutes from '../pages/card/routes.ts'
import autoRoutes from '../pages/automatic/routes.ts'
import Error404 from '../pages/error/Error404.vue'
import adminRoutes from "../pages/admin/routes.ts";
const routes = [
...cardRoutes,
...authRoutes,
...payRoutes,
...serviceRoutes,
...employeeRoutes,
...customerRoutes,
...oilRoutes,
...autoRoutes,
...adminRoutes,
{
path: '/',
name: 'home',
component: Home,
},
// Error Pages
{
path: '/:catchAll(.*)*',
component: Error404,
},
]
let router = createRouter({
history: createWebHistory(),
routes,
})
export default router
//sourceMappingURL=index.ts.map

1
src/services/auth.header.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export default function authHeader(): Record<string, string>;

View File

@@ -0,0 +1,12 @@
export default function authHeader (): Record<string, string> {
let user_token = localStorage.getItem('auth_user')
let auth_token = localStorage.getItem('auth_token')
if (user_token && auth_token) {
return { 'Authorization': 'bearer ' + auth_token };
}
else {
return {'Authorization': 'None'};
}
}

38
src/stores/auth.store.js Normal file
View File

@@ -0,0 +1,38 @@
import { defineStore } from 'pinia';
import { fetchWrapper } from '@/helpers';
import { router } from '@/router';
const baseUrl = `${import.meta.env.VITE_BASE_URL}/users`;
export const useAuthStore = defineStore({
id: 'auth',
state: () => ({
// initialize state from local storage to enable user to stay logged in
user: JSON.parse(localStorage.getItem('user')),
returnUrl: null
}),
actions: {
async login(username, password) {
const user = await fetchWrapper.post(`${baseUrl}/authenticate`,
{ username, password });
// update pinia state
this.user = user;
// store user details and jwt in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify(user));
// redirect to previous url or default to home page
router.push(this.returnUrl || '/');
},
logout() {
this.user = null;
localStorage.removeItem('user');
router.push('/account/login');
}
}
});

64
src/stores/users.store.js Normal file
View File

@@ -0,0 +1,64 @@
import { defineStore } from 'pinia';
import { fetchWrapper } from '@/helpers';
import { useAuthStore } from '@/stores';
const baseUrl = `${import.meta.env.VITE_BASE_URL}/auth`;
export const useUsersStore = defineStore({
id: 'users',
state: () => ({
users: {},
user: {}
}),
actions: {
async register(user) {
await fetchWrapper.post(`${baseUrl}/register`, user);
},
async getAll() {
this.users = { loading: true };
try {
this.users = await fetchWrapper.get(baseUrl);
} catch (error) {
this.users = { error };
}
},
async getById(id) {
this.user = { loading: true };
try {
this.user = await fetchWrapper.get(`${baseUrl}/${id}`);
} catch (error) {
this.user = { error };
}
},
async update(id, params) {
await fetchWrapper.put(`${baseUrl}/${id}`, params);
// update stored user if the logged-in user updated their own record
const authStore = useAuthStore();
if (id === authStore.user.id) {
// update local storage
const user = { ...authStore.user, ...params };
localStorage.setItem('user', JSON.stringify(user));
// update auth user in pinia state
authStore.user = user;
}
},
async delete(id) {
// add isDeleting prop to user being deleted
this.users.find(x => x.id === id).isDeleting = true;
await fetchWrapper.delete(`${baseUrl}/${id}`);
// remove user from list after deleted
this.users = this.users.filter(x => x.id !== id);
// auto logout if the logged in user deleted their own record
const authStore = useAuthStore();
if (id === authStore.user.id) {
authStore.logout();
}
}
}
});

1
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

1085
tailwind.config.js Normal file

File diff suppressed because it is too large Load Diff

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

10
tsconfig.node.json Normal file
View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

13
vite.config.ts Normal file
View File

@@ -0,0 +1,13 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
resolve: {},
build: {
sourcemap: true,
chunkSizeWarningLimit: 1600,
assetsInlineLimit: 2048, // 2kb
},
})