Skip to content

Commit

Permalink
[sale] Add a component to calculate craft investment based on resourc…
Browse files Browse the repository at this point in the history
…es bought + craft cost + runes investment
  • Loading branch information
celestialaly committed Feb 19, 2025
1 parent 3bb794c commit 703a426
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 39 deletions.
1 change: 1 addition & 0 deletions assets/vue/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ declare module 'vue' {
Popover: typeof import('primevue/popover')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Textarea: typeof import('primevue/textarea')['default']
Toast: typeof import('primevue/toast')['default']
ToggleSwitch: typeof import('primevue/toggleswitch')['default']
}
Expand Down
6 changes: 5 additions & 1 deletion assets/vue/src/assets/base.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
@import 'primeicons/primeicons.css';

@import 'primeflex/primeflex.scss';
@import 'primeflex/themes/primeone-dark.css';
@import 'primeflex/themes/primeone-dark.css';

* {
font-family: Helvetica;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/vue/src/package/common/api/ApiPaginator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DataTableFilterEvent, DataTableSortEvent } from "primevue"
import type { DataTableSortEvent } from "primevue"

type PaginatorSearchParameters = {
page: number,
Expand Down
6 changes: 4 additions & 2 deletions assets/vue/src/package/common/helpers/fetchWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ApiException from "../api/ApiException";
import { useAuthStore } from "../stores/authStore";
import { useToastStore } from "../stores/toastStore";

const createQuery =
(baseURL: RequestInfo | URL = '', baseInit?: RequestInit) =>
Expand All @@ -12,10 +13,11 @@ const createQuery =
const { user, logout } = useAuthStore();
if ([401, 403].includes(res.status) && user) {
// auto logout if 401 Unauthorized or 403 Forbidden response returned from api
useToastStore().add({ severity: 'error', summary: `Déconnecté·e`, detail: 'Vous avez été déconecté·e, merci de vous reconnecter', life: 3000 });
logout();
} else {
throw new ApiException(res.status, res.statusText);
}

throw new ApiException(res.status, res.statusText);
}

return res.json() as Promise<T>
Expand Down
14 changes: 12 additions & 2 deletions assets/vue/src/package/sales/component/AddSaleComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import { Sale } from '../domain/Sale';
import CommandSaleController from '../infrastructure/command/CommandSaleController';
import type { Item } from "../domain/Item";
import { useToastStore } from "@/package/common/stores/toastStore";
import CalculateInvestment from "./submodals/CalculateInvestment.vue";
import { SalesEvent } from "../domain/SalesEvent";
const visible = ref(false);
const emit = defineEmits(['sale:create'])
const emit = defineEmits<{
(e: SalesEvent.REFRESH): void
}>()
const commandSaleController = new CommandSaleController();
interface AddSaleForm {
Expand Down Expand Up @@ -46,14 +50,17 @@ const submitForm = () => {
}).catch((err) => {
console.log(err);
})
};
const saveInvestmentPrice = (price: number) => {
state.price = price
};
async function saveSale() {
const sale = Sale.new(state.selectedItem as Item, state.price, state.sellPrice, state.sold);
await commandSaleController.save(sale);
useToastStore().add({ severity: 'success', summary: `Vente ajoutée`, detail: `La vente de votre objet ${sale.item.title} a été ajoutée.`, life: 3000 });
emit('sale:create')
emit(SalesEvent.REFRESH)
closeAndResetForm()
}
Expand Down Expand Up @@ -86,6 +93,9 @@ const closeAndResetForm = () => {
<InputNumber suffix="k" v-model="state.price" :invalid="v$.price.$errors.length > 0" />
<label for="price">Investissement</label>
</IftaLabel>
<InputGroupAddon>
<CalculateInvestment @sales:save-investment-price="saveInvestmentPrice"></CalculateInvestment>
</InputGroupAddon>
</InputGroup>

<InputGroup class="col">
Expand Down
4 changes: 2 additions & 2 deletions assets/vue/src/package/sales/component/SaleComponent.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import QuerySaleController from '../infrastructure/query/QuerySaleController'
import AddSaleComponent from './AddSaleComponent.vue';
import DataTable, { type DataTableFilterEvent, type DataTableFilterMeta, type DataTablePageEvent, type DataTableSortEvent } from 'primevue/datatable';
import DataTable, { type DataTablePageEvent, type DataTableSortEvent } from 'primevue/datatable';
import { FilterMatchMode } from '@primevue/core/api';
import Column from 'primevue/column';
import { computed, onMounted, ref } from 'vue';
Expand Down Expand Up @@ -58,7 +58,7 @@ async function onFilter() {
<template>
<main>
<div class="flex flex-row flex-wrap justify-content-end mb-2">
<AddSaleComponent @sale:create="refreshSalesData()" />
<AddSaleComponent @sales:refresh="refreshSalesData" />
</div>

<DataTable lazy paginator removableSort :value="sales?.data" :totalRecords :first="offset" :rows="limit"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<script setup lang="ts">
import { ref } from "vue";
import { SalesEvent } from "../../domain/SalesEvent";
export interface SaveInvestmentPriceEvent {
price: number
}
const emit = defineEmits<{
(event: SalesEvent.SAVE_INVESTMENT_PRICE, price: number): void
}>()
const visible = ref(false);
const chatlog = ref('');
const craftInvestment = ref(0);
const runeInvestment = ref(0);
const totalInvestment = ref(0);
const calculateTotal = () => {
const re = /\] \(([\d\s]+)/g;
let price = 0;
let lastMatch;
while (lastMatch = re.exec(chatlog.value)) {
if (lastMatch[1]) {
price += parseInt(lastMatch[1].replace(/ /g, ''))
}
// Avoid infinite loop
if(!re.global) break;
}
totalInvestment.value = price + runeInvestment.value + craftInvestment.value
}
const resetForm = () => {
chatlog.value = ''
runeInvestment.value = 0
craftInvestment.value = 0
totalInvestment.value = 0
visible.value = false
}
const submitForm = () => {
emit(SalesEvent.SAVE_INVESTMENT_PRICE, totalInvestment.value)
resetForm()
};
</script>

<template>
<Button icon="pi pi-calculator" severity="contrast" variant="text" @click="visible = true" />

<Dialog v-model:visible="visible" modal header="Calcul de l'investissement" style="width: 60%;">
<form @submit.prevent="submitForm">
<div class="grid">
<div class="col-6">
<IftaLabel>
<Textarea id="chatlog" v-model="chatlog" rows="14" class="w-full" @input="calculateTotal" />
<label for="chatlog">Données de votre chat</label>
</IftaLabel>
</div>

<div class="col-6">
<p class="mt-0">Vous pouvez copier/coller les achats faits à l'HDV pour calculer automatiquement la
somme dépensée :</p>
<img src="@/assets/images/investment_chatlog.png" alt="Chat Log" class=" border-1" />
</div>

<InputGroup class="col-12">
<InputGroupAddon>
<i class="pi pi-hammer"></i>
</InputGroupAddon>
<IftaLabel>
<InputNumber suffix="k" v-model="craftInvestment" @value-change="calculateTotal" />
<label for="runeInvestment">Coût craft</label>
</IftaLabel>
</InputGroup>
<InputGroup class="col-12">
<InputGroupAddon>
<i class="pi pi-sparkles"></i>
</InputGroupAddon>
<IftaLabel>
<InputNumber suffix="k" v-model="runeInvestment" @value-change="calculateTotal" />
<label for="runeInvestment">Investissement en runes</label>
</IftaLabel>
</InputGroup>

<InputGroup class="col-12">
<InputGroupAddon>
<i class="pi pi-dollar"></i>
</InputGroupAddon>
<IftaLabel>
<InputNumber suffix="k" v-model="totalInvestment" disabled />
<label for="totalInvestment">Investissement</label>
</IftaLabel>
</InputGroup>
</div>

<div class="flex justify-content-end gap-2 mt-3">
<Button type="button" severity="secondary" @click="visible = false">Annuler</Button>
<Button type="submit">Valider le calcul</Button>
</div>
</form>
</Dialog>
</template>
1 change: 1 addition & 0 deletions assets/vue/src/package/sales/domain/SalesEvent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum SalesEvent {
REFRESH = 'sales:refresh',
SAVE_INVESTMENT_PRICE = 'sales:save-investment-price'
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import router from '@/router';
import { useVuelidate } from '@vuelidate/core';
import { required, email, sameAs } from '@vuelidate/validators';
import CommandUserController from '../infrastructure/command/CommandUserController';
Expand Down Expand Up @@ -53,6 +54,7 @@ const registerUser = async () => {
await commandUserController.register(user)
useToastStore().add({ severity: 'success', summary: `Compte créé`, detail: `Votre compte vient d'être créé, bienvenue !`, life: 3000 });
resetForm()
router.push('/auth');
}
</script>

Expand Down
93 changes: 62 additions & 31 deletions assets/vue/src/views/HomeView.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,73 @@
<script setup lang="ts">
import { useAuthStore } from '../package/common/stores/authStore';
const authStore = useAuthStore();
</script>

<template>
<Suspense>
<div class="min-h-[40rem] lg:min-h-0 bg-surface-0 dark:bg-surface-900 flex lg:flex-row flex-col">
<div class="flex lg:flex lg:flex-row flex-col justify-center md:justify-normal h-full flex-1">
<div class="relative flex-1 z-20 flex items-center justify-center">
<div class="flex items-center justify-center h-full">
<div class="w-full max-w-2xl px-6 py-12 lg:p-12 xl:p-16 text-center lg:text-left">
<h1
class="text-4xl xl:text-5xl font-bold text-surface-0 lg:text-surface-900 dark:text-surface-0 mb-4 !leading-tight">
<span class="block">Gérer plus simplement</span>
<span class="block text-primary">vos ventes Dofus</span>
</h1>

<p
class="text-surface-0/90 lg:text-surface-700 dark:text-surface-200 text-xl leading-normal mb-4 max-w-xl lg:max-w-none">
<ul class="list-none line-height-3 p-0">
<li>Modification du prix avec recalcul automatique de la taxe HDV</li>
<li>Calcul auto des achats effectués en HDV via un simple copier/coller</li>
<li>Statistiques de ventes (investissement, profit...)</li>
</ul>
</p>

<div class="flex items-center gap-4 justify-center lg:justify-start">
<RouterLink to="/register">
<Button label="S'inscrire" icon="pi pi-user" />
</RouterLink>
</div>
<div class="min-h-[40rem] lg:min-h-0 bg-surface-0 dark:bg-surface-900 flex lg:flex-row flex-col">
<div class="flex lg:flex lg:flex-row flex-col justify-center md:justify-normal h-full flex-1">
<div class="relative flex-1 z-20 flex items-center justify-center">
<div class="flex items-center justify-center h-full">
<div class="w-full max-w-2xl px-6 py-12 lg:p-12 xl:p-16 text-center lg:text-left">
<h1
class="text-4xl xl:text-5xl font-bold text-surface-0 lg:text-surface-900 dark:text-surface-0 mb-4 !leading-tight">
<span class="block">Gérer plus simplement</span>
<span class="block text-primary">vos ventes Dofus</span>
</h1>

<p
class="text-surface-0/90 lg:text-surface-700 dark:text-surface-200 text-xl leading-normal mb-4 max-w-xl lg:max-w-none">
<ul class="list-none line-height-3 p-0">
<li>Modification du prix avec recalcul automatique de la taxe HDV</li>
<li>Statistiques de ventes (investissement, profit...)</li>
</ul>
</p>

<div class="flex items-center gap-4 justify-center lg:justify-start" v-if="!authStore.user">
<RouterLink to="/register">
<Button label="S'inscrire" icon="pi pi-user" />
</RouterLink>
</div>
</div>
</div>
</div>

<div class="absolute lg:relative inset-0 lg:inset-auto flex-1 mt-2">
<div class="absolute lg:hidden inset-0 bg-surface-900/60 dark:bg-surface-900/80 z-10" />
<img src="@/assets/sales.png" alt="Ventes" class="h-full object-cover border-2" />
</div>
<div class="absolute lg:relative inset-0 lg:inset-auto flex-1 mt-2">
<div class="absolute lg:hidden inset-0 bg-surface-900/60 dark:bg-surface-900/80 z-10" />
<img src="@/assets/images/sales.png" alt="Ventes" class="h-full object-cover border-2" />
</div>
</div>
</div>

<hr class="mt-4 border-primary-500">

<div class="min-h-[40rem] lg:min-h-0 bg-surface-0 dark:bg-surface-900 flex lg:flex-row flex-col mt-4">
<div class="flex lg:flex lg:flex-row flex-col justify-center md:justify-normal h-full flex-1">
<div class="absolute lg:relative inset-0 lg:inset-auto flex-1 mt-2">
<div class="absolute lg:hidden inset-0 bg-surface-900/60 dark:bg-surface-900/80 z-10" />
<img src="@/assets/images/sales_investment.png" alt="Ventes" class="h-full object-cover border-1 border-gray-500" style="max-width: 800px;" />
</div>
</div>
</Suspense>

<div class="relative flex-1 z-20 flex items-center justify-center">
<div class="flex items-center justify-center h-full">
<div class="w-full max-w-2xl px-6 py-12 lg:p-12 xl:p-16 text-center lg:text-left">
<h1
class="text-4xl xl:text-5xl font-bold text-surface-0 lg:text-surface-900 dark:text-surface-0 mb-4 !leading-tight">
<span class="block">Calculer automatiquement</span>
<span class="block text-primary">l'investissement des crafts</span>
</h1>

<p
class="text-surface-0/90 lg:text-surface-700 dark:text-surface-200 text-xl leading-normal mb-4 max-w-xl lg:max-w-none">
<ul class="list-none line-height-3 p-0">
<li>Calcul auto des achats effectués en HDV via un simple copier/coller</li>
<li>Prise en compte du paiement du coût du craft + dépenses en runes</li>
</ul>
</p>
</div>
</div>
</div>
</div>
</template>

0 comments on commit 703a426

Please sign in to comment.