Whole site refactor. Added pinia stores and authentication capability.

This commit is contained in:
2024-06-27 09:24:47 +02:00
parent 93c015fcb7
commit 87c8579e9e
18 changed files with 717 additions and 258 deletions

221
package-lock.json generated
View File

@@ -9,10 +9,15 @@
"version": "0.0.0",
"dependencies": {
"@vuepic/vue-datepicker": "^8.7.0",
"axios": "^1.7.2",
"bulma": "^1.0.1",
"cors": "^2.8.5",
"pinia": "^2.1.7",
"vee-validate": "^4.13.1",
"vue": "^3.4.21",
"vue-router": "^4.3.0"
"vue-router": "^4.3.3",
"vue3-cookies": "^1.0.6",
"yup": "^1.4.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
@@ -1328,6 +1333,21 @@
"node": ">=8"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1457,6 +1477,17 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/computeds": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz",
@@ -1550,6 +1581,14 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -1989,6 +2028,38 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -2363,6 +2434,25 @@
"node": ">=8.6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
@@ -2627,6 +2717,56 @@
"node": ">=0.10"
}
},
"node_modules/pinia": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz",
"integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.3.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.8",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
"integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/postcss": {
"version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
@@ -2703,6 +2843,16 @@
"node": ">=6.0.0"
}
},
"node_modules/property-expr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
"integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -2983,6 +3133,11 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/tiny-case": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2995,6 +3150,11 @@
"node": ">=8.0"
}
},
"node_modules/toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
},
"node_modules/ts-api-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -3079,6 +3239,29 @@
"node": ">= 0.8"
}
},
"node_modules/vee-validate": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.13.1.tgz",
"integrity": "sha512-JAlUWTBHg0z66n+v66mrtE9IC1xmVCggzpyc7UXCNkizVok8Zgt1VAVjobSxA/0N19Zn6v6hRfjoYciYH/Z11Q==",
"dependencies": {
"@vue/devtools-api": "^6.6.1",
"type-fest": "^4.8.3"
},
"peerDependencies": {
"vue": "^3.4.26"
}
},
"node_modules/vee-validate/node_modules/type-fest": {
"version": "4.20.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.20.1.tgz",
"integrity": "sha512-R6wDsVsoS9xYOpy8vgeBlqpdOyzJ12HNfQhC/aAKWM3YoCV9TtunJzh/QpkMgeDhkoynDcw5f1y+qF9yc/HHyg==",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/vite": {
"version": "5.2.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
@@ -3179,9 +3362,9 @@
}
},
"node_modules/vue-router": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz",
"integrity": "sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==",
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.3.tgz",
"integrity": "sha512-8Q+u+WP4N2SXY38FDcF2H1dUEbYVHVPtPCPZj/GTZx8RCbiB8AtJP9+YIxn4Vs0svMTNQcLIzka4GH7Utkx9xQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.1"
},
@@ -3219,6 +3402,14 @@
"typescript": "*"
}
},
"node_modules/vue3-cookies": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/vue3-cookies/-/vue3-cookies-1.0.6.tgz",
"integrity": "sha512-a1UvVD0qIgxyOqjlSOwnLnqAnz8ASltugEv8yX+96i/WGZAN9fEDci7xO4HIWZE1uToUnRq9JnFhvfDCSo45OA==",
"dependencies": {
"vue": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3269,6 +3460,28 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yup": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz",
"integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==",
"dependencies": {
"property-expr": "^2.0.5",
"tiny-case": "^1.0.3",
"toposort": "^2.0.2",
"type-fest": "^2.19.0"
}
},
"node_modules/yup/node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}

View File

@@ -14,10 +14,15 @@
},
"dependencies": {
"@vuepic/vue-datepicker": "^8.7.0",
"axios": "^1.7.2",
"bulma": "^1.0.1",
"cors": "^2.8.5",
"pinia": "^2.1.7",
"vee-validate": "^4.13.1",
"vue": "^3.4.21",
"vue-router": "^4.3.0"
"vue-router": "^4.3.3",
"vue3-cookies": "^1.0.6",
"yup": "^1.4.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",

View File

@@ -1,176 +1,10 @@
<template>
<NavBar @form="switchToFrom" @order="switchToOrders"/>
<div v-if="isLoading">
<LoadingComponent/>
</div>
<div v-else>
<div v-if="isForm">
<MainForm
v-if="order == undefined || order.MZN_Bufor==1"
:is-dark-theme="isDarkTheme"
v-model:order-uuid="uuid"
v-model:contractors="contractors"
v-model:categories="categories"
v-model:contractor="contractor"
v-model:delivery-date="deliveryDate"
v-model:show-modal="showModal"
/>
<ConfirmedForm v-else-if="order.MZN_Bufor==0"
:order-date="orderDate"
:uuid = "uuid"
:delivery-date="deliveryDate"
v-model:contractor="contractor"
v-model:categories="categories"
v-model:order="order">
</ConfirmedForm>
</div>
<OrdersSelector class="box is-shadowless" v-else-if="isOrders"
v-model:orders="orders"
@order="viewOrder"
/>
</div>
<ConfirmationModal v-show="showModal" @close="showModal = false" @confirm="closeModal" :order-uuid="uuid"></ConfirmationModal>
<RouterView />
</template>
<script setup lang="ts">
import './assets/style.scss'
import type { Category, Contractor, Order } from '@/main'
import { ref } from 'vue'
const contractors = ref<Array<Contractor>>();
const contractor = ref<Contractor>();
const categories = ref<Array<Category>>();
const orders = ref<Array<Order>>(new Array<Order>());
const order = ref<Order>();
const deliveryDate = ref<Date>();
const orderDate = ref<Date>();
const uuid = ref<string>();
const isForm = ref<boolean>(true);
const isOrders = ref<boolean>(false);
const showModal = ref<boolean>(false);
const isDarkTheme = ref<boolean>(false);
const isLoading = ref<boolean>(true);
async function fetchContractors() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/kontrahenci');
contractors.value = await response.json();
}
async function fetchCategories() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/towary');
categories.value = await response.json();
if(categories.value != undefined) {
for (let category of categories.value) {
for (let product of category.Towary) {
product.Options = new Array(product.Twr_JM);
product.ChosenOption = product.Twr_JM;
if (product.Twr_JMZ != null) {
product.Options.push(product.Twr_JMZ);
}
}
}
}
}
async function fetchOrdersInBuffer() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienia/bufor');
let ordersTemp : Array<Order> = await response.json();
orders.value.push(...ordersTemp);
}
async function fetchOrdersOutOfBuffer() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienia');
let ordersTemp : Array<Order> = await response.json();
orders.value.push(...ordersTemp);
}
async function fetchData() {
await fetchContractors();
await fetchCategories();
await fetchOrdersInBuffer();
await fetchOrdersOutOfBuffer();
isLoading.value = false;
}
function switchToFrom() {
if(!isForm.value) {
isForm.value = true;
isOrders.value = false;
}
}
async function switchToOrders() {
if(!isOrders.value) {
isLoading.value = true;
isForm.value = false;
isOrders.value = true;
orders.value = new Array<Order>();
await fetchOrdersInBuffer();
await fetchOrdersOutOfBuffer();
isLoading.value = false;
}
}
function checkTheme() {
isDarkTheme.value = !!window?.matchMedia?.('(prefers-color-scheme:dark)')?.matches;
}
function viewOrder(event : Event) {
console.log('parent');
isForm.value=true;
isOrders.value=false;
window.scrollTo(0, 0);
console.log(event.MZN_UUID);
if (categories.value == undefined) return;
isLoading.value = true;
loadOrder(event.MZN_UUID, false);
}
function closeModal() {
showModal.value = false;
if (uuid.value != undefined) {
isLoading.value = true;
loadOrder(uuid.value, true);
}
}
async function loadOrder(uuid: string, confirmed: boolean) {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienie/' + uuid);
let tempOrder = await response.json();
if(confirmed) {
tempOrder.MZN_Bufor = 0;
}
contractor.value = contractors.value?.find((contractor) => contractor.Knt_KntId == tempOrder.MZN_PodID);
deliveryDate.value = new Date(tempOrder.MZN_DataDos);
orderDate.value = new Date(tempOrder.MZN_DataZam);
order.value = tempOrder;
if(categories.value == undefined) {
isLoading.value = false;
return;
}
console.log(order.value);
for(let orderProduct of tempOrder.MZamElem){
for(let category of categories.value) {
let product = category.Towary.find(product => (product.Twr_TwrId == orderProduct.MZE_TwrId));
if(product != undefined && orderProduct.MZE_TwrCena != null) {
product.Twr_Cena = orderProduct.MZE_TwrCena.slice(0, -2);
product.Quantity = orderProduct.MZE_TwrIlosc.slice(0, -2);
category.isVisible = true;
break;
}
}
}
isLoading.value = false;
}
fetchData();
checkTheme();
import { RouterView } from 'vue-router'
</script>
<style>

View File

@@ -1,17 +1,29 @@
<script setup lang="ts">
const emit = defineEmits(['close', 'confirm']);
import { useOrdersStore } from '@/stores/orders.store'
import { storeToRefs } from 'pinia'
import { axiosInstance } from '@/main'
import { useSiteControlStore } from '@/stores/siteControl.store'
import { useContractorsStore } from '@/stores/contractors.store'
import { useCategoriesStore } from '@/stores/categories.store'
const props = defineProps(
{
orderUuid : String
const ordersStore = useOrdersStore();
const siteControlStore = useSiteControlStore();
const contractorStore = useContractorsStore();
const categoriesStore = useCategoriesStore();
const { contractor, contractors } = storeToRefs(contractorStore);
const { categories } = storeToRefs(categoriesStore);
const { uuid } = storeToRefs(ordersStore);
const { showConfirmationModal, isLoading} = storeToRefs(siteControlStore);
async function confirmOrder() {
await axiosInstance.put('/zamowienie/' + uuid.value);
showConfirmationModal.value = false;
if (uuid.value != undefined) {
isLoading.value = true;
await ordersStore.loadOrder(uuid.value, true, contractor, contractors, categories);
isLoading.value = false;
}
);
function confirmOrder() {
emit('confirm');
fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienie/' + props.orderUuid, {
method: 'PUT'
});
}
</script>

View File

@@ -1,16 +1,19 @@
<script setup lang="ts">
import type { Category, Contractor, Order } from '@/main'
import VueDatePicker from '@vuepic/vue-datepicker'
import { useOrdersStore } from '@/stores/orders.store'
import { storeToRefs } from 'pinia'
import { useCategoriesStore } from '@/stores/categories.store'
import { useContractorsStore } from '@/stores/contractors.store'
const order = defineModel<Order>('order');
const categories = defineModel<Array<Category>>('categories');
const contractor = defineModel<Contractor>('contractor');
const ordersStore = useOrdersStore();
const categoriesStore = useCategoriesStore();
const contractorsStore = useContractorsStore();
const props = defineProps({
orderDate: Date,
uuid: String,
deliveryDate: Date
})
const { order, uuid} = storeToRefs(ordersStore);
const { categories } = storeToRefs(categoriesStore);
const { contractor } = storeToRefs(contractorsStore);
function cancelOrder(event: Event) {
event.preventDefault();

View File

@@ -0,0 +1,50 @@
<script setup lang="ts">
import { axiosInstance } from '@/main'
import type { VueCookies } from 'vue3-cookies/dist/interfaces'
import { inject } from 'vue'
const emit = defineEmits(['close']);
function sendLogin() {
emit('close');
axiosInstance.post('/login', {
username: 'testowyj',
password: 'beihiegei5Fied0b'
}, {
withCredentials: true
});
const $cookies = inject<VueCookies>('$cookies');
console.log($cookies);
}
</script>
<template>
<div>
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card p-3">
<header class="modal-card-head">
<p class="modal-card-title">Logowanie</p>
<button class="delete" aria-label="close" @click="$emit('close')"></button>
</header>
<section class="modal-card-body">
<form>
</form>
</section>
<footer class="modal-card-foot">
<div class="buttons">
<button class="button is-success" @click="sendLogin">Zaloguj się</button>
<button class="button" @click="$emit('close')">Anuluj</button>
</div>
</footer>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,19 +1,23 @@
<script setup lang="ts">
import VueDatePicker from '@vuepic/vue-datepicker';
import type { Category, Contractor, OrderProduct } from '@/main';
import { axiosInstance, type Category, type Contractor, type OrderProduct } from '@/main'
import { useCategoriesStore } from '@/stores/categories.store'
import { useContractorsStore } from '@/stores/contractors.store'
import { useOrdersStore } from '@/stores/orders.store'
import { storeToRefs } from 'pinia'
import { useSiteControlStore } from '@/stores/siteControl.store'
const props = defineProps(['isDarkTheme']);
const uuid = defineModel<string>('orderUuid');
const contractors = defineModel<Array<Contractor>>('contractors');
const contractor = defineModel<Contractor>('contractor');
const deliveryDate = defineModel<Date>('deliveryDate');
const categories = defineModel<Array<Category>>('categories');
const showModal = defineModel<boolean>('showModal');
const categoriesStore = useCategoriesStore();
const contractorsStore = useContractorsStore();
const ordersStore = useOrdersStore();
const siteControlStore = useSiteControlStore();
const { contractor, contractors } = storeToRefs(contractorsStore);
const { deliveryDate, uuid } = storeToRefs(ordersStore);
const { categories } = storeToRefs(categoriesStore);
const { showConfirmationModal, isDarkTheme } = storeToRefs(siteControlStore);
function createJSON(event: Event) {
console.log(contractor.value);
event.preventDefault();
const json = {
MZN_UUID: uuid.value,
@@ -42,16 +46,15 @@ function createJSON(event: Event) {
}
}
}
fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienie', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(json)
})
.then(response => response.json())
.then(response => uuid.value = response.MZN_UUID);
axiosInstance.post('/zamowienie', JSON.stringify(json)).then( response => {
uuid.value = response.data.MZN_UUID;
});
}
function setConfirmationModal(event : Event) {
event.preventDefault();
showConfirmationModal.value = true;
}
</script>
@@ -59,8 +62,10 @@ function createJSON(event: Event) {
<form class="box" @submit="createJSON">
<div class="mb-3">
<div class="box">
<h1 class="is-large mb-3"><b>ZAMÓWIENIE</b></h1>
<h1 class="is-large mb-3" v-if="uuid != null" ><b>{{ uuid }}</b></h1>
<div class="mb-3">
<h1 class="title is-5"><b>ZAMÓWIENIE</b></h1>
<h1 class="subtitle is-5" v-if="uuid != undefined" ><b>{{ uuid }}</b></h1>
</div>
<div class="field mb-5">
<label class="label is-small">NIP</label>
<div class="field">
@@ -83,13 +88,13 @@ function createJSON(event: Event) {
v-bind:dark = "isDarkTheme"/>
</div>
</div>
<button class="button is-primary mt-5">Submit</button>
<button class="button is-primary mt-5 ml-3" @click="showModal = true">Potwierdź</button>
<button class="button is-info mt-5">Submit</button>
<button class="button is-info mt-5 ml-3" @click="setConfirmationModal">Potwierdź</button>
</div>
</div>
<div v-for="category in categories" :key="category.Kod">
<div class="box mb-3" >
<h1 class="is-large mb-3"><b>{{ category.Kod }}</b></h1>
<h1 class="title is-5 mb-3 mb-3"><b>{{ category.Kod }}</b></h1>
<div class="field" v-for="(product, index) in category.Towary" :key="product.Twr_Nazwa">
<label class="label is-small">{{ product.Twr_Nazwa }}</label>
<div class="columns is-mobile">
@@ -134,10 +139,10 @@ function createJSON(event: Event) {
</div>
<div class="columns mt-1 is-variable is-mobile">
<div class = "column is-6">
<button class="button is-primary is-fullwidth is-large">Submit</button>
<button class="button is-info is-fullwidth is-large">Submit</button>
</div>
<div class = "is-large column is-6 ml-3">
<button class="button is-primary is-fullwidth is-large" @click="parseOrderJSON">Potwierdź</button>
<button class="button is-info is-fullwidth is-large" @click="showConfirmationModal = true">Potwierdź</button>
</div>
</div>
</form>
@@ -151,6 +156,7 @@ function createJSON(event: Event) {
--dp-menu-border-color: var(--bulma-border);
--dp-border-color-hover: var(--bulma-border);
--dp-border-color-focus: var(--bulma-border);
--dp-primary-color: var(--bulma-info-00);
}
}
@@ -160,6 +166,8 @@ function createJSON(event: Event) {
--dp-menu-border-color: var(--bulma-border);
--dp-border-color-hover: var(--bulma-border);
--dp-border-color-focus: var(--bulma-border);
--dp-primary-color: var(--bulma-info);
--dp-primary-text-color: #000;
}
}
</style>

View File

@@ -1,24 +1,25 @@
<script setup lang="ts">
import { ref } from 'vue'
const emit = defineEmits(['form', 'order']);
import { useSiteControlStore } from '@/stores/siteControl.store'
const activator = ref(false);
const siteControlStore = useSiteControlStore();
function makeBurger() {
activator.value = !activator.value
return activator
}
function clickForm() {
emit('form');
siteControlStore.switchToFrom();
if(activator.value) {
activator.value = false;
}
}
function clickOrders() {
emit('order');
siteControlStore.switchToOrders();
if(activator.value) {
activator.value = false;
}

View File

@@ -1,26 +1,26 @@
<script setup lang="ts">
import VueDatePicker from '@vuepic/vue-datepicker';
import { onRenderTriggered, ref, watch } from 'vue'
import type { Order } from '@/main'
import { ref, watch } from 'vue'
import { useOrdersStore } from '@/stores/orders.store'
import { storeToRefs } from 'pinia'
import { useSiteControlStore } from '@/stores/siteControl.store'
const ordersStore = useOrdersStore();
const siteControlStore = useSiteControlStore();
const searchOrderDate = ref<Date>();
const isOutOfBufor = ref<boolean>(false);
const isOutOfBuffer = ref<boolean>(false);
const isInBufor = ref<boolean>(false);
const orders = defineModel<Array<Order>>('orders');
const emit = defineEmits<{
order: [order: Order]
}>()
const { orders } = storeToRefs(ordersStore);
watch(isInBufor, (val) => {
if(val && val == isOutOfBufor.value) {
isOutOfBufor.value = false;
if(val && val == isOutOfBuffer.value) {
isOutOfBuffer.value = false;
}
},{
immediate: true
});
watch(isOutOfBufor, (val) => {
watch(isOutOfBuffer, (val) => {
if(val && val == isInBufor.value) {
isInBufor.value = false;
}
@@ -28,30 +28,16 @@ watch(isOutOfBufor, (val) => {
immediate: true
});
function viewOrder(event: Event | undefined) {
let tempOrder = orders.value?.find(order => (order.MZN_UUID == event?.target?.name));
if (tempOrder == undefined) return;
emit('order', tempOrder);
}
async function fetchOrdersInBuffer() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienia/bufor');
let ordersTemp : Array<Order> = await response.json();
orders.value = ordersTemp;
}
async function fetchOrdersOutOfBuffer() {
const response = await fetch('https://zamowienia.mleczarnia-kuzma.pl/api/zamowienia');
let ordersTemp : Array<Order> = await response.json();
orders.value = ordersTemp;
function viewOrder(uuid : string) {
siteControlStore.viewOrder(uuid);
}
async function fetchOrders(event : Event) {
event.preventDefault();
if(isInBufor.value) {
fetchOrdersInBuffer();
} else if (isOutOfBufor.value) {
fetchOrdersOutOfBuffer();
orders.value = await ordersStore.fetchOrdersInBuffer();
} else if (isOutOfBuffer.value) {
orders.value = await ordersStore.fetchOrdersOutOfBuffer();
}
}
@@ -75,7 +61,7 @@ async function fetchOrders(event : Event) {
<label class="label is-small">Zamówienie potwierdzone?</label>
<div class="control">
<label class="checkbox mr-5">
<input type="checkbox" v-model="isOutOfBufor"/>
<input type="checkbox" v-model="isOutOfBuffer"/>
Tak
</label>
<label class="checkbox">
@@ -133,7 +119,7 @@ async function fetchOrders(event : Event) {
value="Nie"
readonly/>
</div>
<button class="button is-primary is-small is-expanded" @click="viewOrder" :name="order.MZN_UUID">Podgląd</button>
<button class="button is-primary is-small is-expanded" @click="viewOrder(order.MZN_UUID)" :name="order.MZN_UUID">Podgląd</button>
</div>
</div>
</div>

View File

@@ -8,10 +8,35 @@ import MainForm from '@/components/MainForm.vue';
import OrdersSelector from '@/components/OrdersSelector.vue'
import ConfirmedForm from '@/components/ConfirmedForm.vue'
import LoadingComponent from '@/components/LoadingComponent.vue'
import axios from 'axios'
import LoginModal from '@/components/LoginModal.vue'
import { createPinia } from 'pinia'
import VueCookies from 'vue3-cookies'
import { router } from '@/router/router'
import { useSiteControlStore } from '@/stores/siteControl.store'
import { useCategoriesStore } from '@/stores/categories.store'
import { useOrdersStore } from '@/stores/orders.store'
import { useContractorsStore } from '@/stores/contractors.store'
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.use(VueCookies);
app.use(router);
useOrdersStore();
useContractorsStore();
useCategoriesStore();
useSiteControlStore();
export const axiosInstance = axios.create({
baseURL: 'https://zamowienia.mleczarnia-kuzma.pl/api',
withCredentials: true
});
const app = createApp(App)
app.component('VueDatePicker', VueDatePicker);
app.component('ConfirmationModal', ConfirmationModal);
app.component('LoginModal', LoginModal);
app.component('NavBar', NavBar);
app.component('MainForm', MainForm);
app.component('OrdersSelector', OrdersSelector);
@@ -56,7 +81,7 @@ export interface Contractor {
Knt_Nazwa1: string,
Knt_Nazwa2: string,
Knt_Nazwa3: string,
Knt_Niekatywny: number,
Knt_Nieaktywny: number,
Knt_NipE: string,
Knt_NrDomu: string,
Knt_OpiekunId: number,

22
src/router/router.ts Normal file
View File

@@ -0,0 +1,22 @@
import { createRouter, createWebHistory } from 'vue-router';
import { MainView, LoginView } from '@/views';
export const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
linkActiveClass: 'active',
routes: [
{ path: '/', component: MainView },
{ path: '/login', component: LoginView }
]
});
router.beforeEach(async (to) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/login'];
const authRequired = !publicPages.includes(to.path);
//
// if (authRequired) {
// return '/login';
// }
});

View File

@@ -0,0 +1,27 @@
import { defineStore } from 'pinia'
import type { Category } from '@/main'
import { ref } from 'vue'
import { axiosInstance } from '@/main'
export const useCategoriesStore = defineStore('categories', () => {
const categories = ref<Array<Category>>([]);
async function fetchCategories() {
const response = await axiosInstance.get('/towary', {withCredentials: true});
categories.value = response.data;
if(categories.value != undefined) {
for (const category of categories.value) {
for (const product of category.Towary) {
product.Options = new Array(product.Twr_JM);
product.ChosenOption = product.Twr_JM;
if (product.Twr_JMZ != null) {
product.Options.push(product.Twr_JMZ);
}
}
}
}
}
return {categories, fetchCategories}
})

View File

@@ -0,0 +1,21 @@
import { defineStore } from 'pinia'
import type { Contractor } from '@/main'
import { ref } from 'vue'
import { axiosInstance } from '@/main'
export const useContractorsStore = defineStore('contractors', () => {
const contractors = ref<Array<Contractor>>([]);
contractors.value=[];
const contractor = ref<Contractor>();
async function fetchContractors() {
const response = await axiosInstance.get('/kontrahenci', {withCredentials: true});
console.log(response);
console.log(contractors.value);
contractors.value = [];
contractors.value.push(...response.data);
}
return {contractors, contractor, fetchContractors}
})

View File

@@ -0,0 +1,71 @@
import { defineStore } from 'pinia'
import type { Category, Contractor, Order } from '@/main'
import { type Ref, ref } from 'vue'
import { axiosInstance } from '@/main'
export const useOrdersStore = defineStore('orders', () => {
const orders = ref<Array<Order>>([]);
const order = ref<Order>();
const uuid = ref<string>();
const deliveryDate = ref<Date>();
const orderDate = ref<Date>();
async function fetchOrders() {
orders.value=[];
let ordersTemp : Array<Order> = await fetchOrdersInBuffer();
orders.value.push(...ordersTemp);
ordersTemp = await fetchOrdersOutOfBuffer();
orders.value.push(...ordersTemp);
}
async function fetchOrdersOutOfBuffer() : Promise<Array<Order>> {
const response = await axiosInstance.get('/zamowienia', {withCredentials: true});
const ordersTemp : Array<Order> = response.data;
return ordersTemp;
}
async function fetchOrdersInBuffer() : Promise<Array<Order>> {
const response = await axiosInstance.get('/zamowienia/bufor', {withCredentials: true});
const ordersTemp : Array<Order> = response.data;
return ordersTemp;
}
async function fetchOrder(uuid : string) {
}
async function loadOrder(uuidString: string, confirmed: boolean, contractor: Ref<Contractor|undefined>, contractors: Ref<Array<Contractor>>, categories: Ref<Array<Category>>) {
const response = await axiosInstance.get('/zamowienie/' + uuidString);
const tempOrder = response.data;
console.log(tempOrder);
if(confirmed) {
tempOrder.MZN_Bufor = 0;
}
contractor.value = <Contractor>contractors.value?.find((contractor) => contractor.Knt_KntId == tempOrder.MZN_PodID);
deliveryDate.value = new Date(tempOrder.MZN_DataDos);
orderDate.value = new Date(tempOrder.MZN_DataZam);
uuid.value = uuidString;
order.value = tempOrder;
if(categories.value == undefined) {
return;
}
for(const orderProduct of tempOrder.MZamElem){
for(const category of categories.value) {
const product = category.Towary.find(product => (product.Twr_TwrId == orderProduct.MZE_TwrId));
if(product != undefined && orderProduct.MZE_TwrCena != null) {
product.Twr_Cena = orderProduct.MZE_TwrCena.slice(0, -2);
product.Quantity = orderProduct.MZE_TwrIlosc.slice(0, -2);
category.isVisible = true;
break;
}
}
}
}
return {orders, order, uuid, deliveryDate, orderDate, fetchOrders, fetchOrdersInBuffer, fetchOrdersOutOfBuffer, loadOrder}
})

View File

@@ -0,0 +1,55 @@
import { defineStore, storeToRefs } from 'pinia'
import { ref } from 'vue'
import { useOrdersStore } from '@/stores/orders.store'
import type { Order } from '@/main'
import { useContractorsStore } from '@/stores/contractors.store'
import { useCategoriesStore } from '@/stores/categories.store'
export const useSiteControlStore = defineStore('siteControl', () => {
const isForm = ref<boolean>(true);
const isOrders = ref<boolean>(false);
const showConfirmationModal = ref<boolean>(false);
const isDarkTheme = ref<boolean>(false);
const isLoading = ref<boolean>(true);
function switchToFrom() {
if(!isForm.value) {
isForm.value = true;
isOrders.value = false;
}
}
async function switchToOrders() {
if(!isOrders.value) {
const orderStore = useOrdersStore();
const { orders } = storeToRefs(orderStore);
isLoading.value = true;
isForm.value = false;
isOrders.value = true;
orders.value = new Array<Order>();
orders.value.push(... await orderStore.fetchOrdersInBuffer());
orders.value.push(... await orderStore.fetchOrdersOutOfBuffer());
isLoading.value = false;
}
}
function checkTheme() {
isDarkTheme.value = !!window?.matchMedia?.('(prefers-color-scheme:dark)')?.matches;
}
async function viewOrder(uuid : string) {
const orderStore = useOrdersStore();
const contractorsStore = useContractorsStore();
const categoriesStore = useCategoriesStore();
isForm.value = true;
isOrders.value = false;
isLoading.value = true;
window.scrollTo(0, 0);
const { contractor, contractors } = storeToRefs(contractorsStore);
const { categories } = storeToRefs(categoriesStore);
await orderStore.loadOrder(uuid, false, contractor, contractors, categories);
isLoading.value=false;
}
return {isForm, isOrders, isLoading, showConfirmationModal, isDarkTheme, switchToFrom, switchToOrders, checkTheme, viewOrder};
})

47
src/views/LoginView.vue Normal file
View File

@@ -0,0 +1,47 @@
<script setup lang="ts">
import { Form, Field } from 'vee-validate';
import * as Yup from 'yup';
const schema = Yup.object().shape({
username: Yup.string().required('Username is required'),
password: Yup.string().required('Password is required')
});
function onSubmit(values : any) {
const { username, password } = values;
}
</script>
<template>
<div>
<div class="alert alert-info">
Username: test<br />
Password: test
</div>
<h2>Login</h2>
<Form @submit="onSubmit" :validation-schema="schema" v-slot="{ errors, isSubmitting }">
<div class="form-group">
<label>Username</label>
<Field name="username" type="text" class="form-control" :class="{ 'is-invalid': errors.username }" />
<div class="invalid-feedback">{{errors.username}}</div>
</div>
<div class="form-group">
<label>Password</label>
<Field name="password" type="password" class="form-control" :class="{ 'is-invalid': errors.password }" />
<div class="invalid-feedback">{{errors.password}}</div>
</div>
<div class="form-group">
<button class="btn btn-primary" :disabled="isSubmitting">
<span v-show="isSubmitting" class="spinner-border spinner-border-sm mr-1"></span>
Login
</button>
</div>
<div v-if="errors.apiError" class="alert alert-danger mt-3 mb-0">{{errors.apiError}}</div>
</Form>
</div>
</template>
<style scoped>
</style>

77
src/views/MainView.vue Normal file
View File

@@ -0,0 +1,77 @@
<template>
<NavBar/>
<div v-if="isLoading">
<LoadingComponent/>
</div>
<div v-else>
<div v-if="isForm">
<MainForm
v-if="order == undefined || order.MZN_Bufor==1"
/>
<ConfirmedForm v-else-if="order.MZN_Bufor==0"/>
</div>
<OrdersSelector class="box is-shadowless" v-else-if="isOrders"
/>
</div>
<ConfirmationModal v-show="showConfirmationModal" @close="showConfirmationModal = false" @confirm="closeConfirmationModal" :order-uuid="uuid"></ConfirmationModal>
</template>
<script setup lang="ts">
import '@/assets/base.css'
import { useContractorsStore } from '@/stores/contractors.store'
import { storeToRefs } from 'pinia'
import { useCategoriesStore } from '@/stores/categories.store'
import { useOrdersStore } from '@/stores/orders.store'
import { useSiteControlStore } from '@/stores/siteControl.store'
const contractorsStore = useContractorsStore();
const categoriesStore = useCategoriesStore();
const ordersStore = useOrdersStore();
const siteControlStore = useSiteControlStore();
const contractors = storeToRefs(contractorsStore).contractors;
const contractor = storeToRefs(contractorsStore).contractor;
const categories = storeToRefs(categoriesStore).categories;
const { uuid, order } = storeToRefs(ordersStore);
const { isForm, isOrders, showConfirmationModal, isLoading } = storeToRefs(siteControlStore);
async function fetchData() {
await categoriesStore.fetchCategories();
await contractorsStore.fetchContractors();
isLoading.value = false;
}
function closeConfirmationModal() {
showConfirmationModal.value = false;
if (uuid.value != undefined) {
isLoading.value = true;
ordersStore.loadOrder(uuid.value, true, contractor, contractors, categories);
}
}
siteControlStore.checkTheme();
fetchData();
</script>
<style>
@media screen and (min-width: 500px) {
.box {
--bulma-box-padding: 1.5rem;
}
}
@media screen and (max-width: 500px) {
.box {
--bulma-box-padding: 0.75rem;
}
}
:root {
min-height: 100vh;
}
body {
min-height: 100vh;
}
</style>

2
src/views/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export { default as LoginView } from "./LoginView.vue";
export { default as MainView } from "./MainView.vue";