feat(market): track user points change

This commit is contained in:
2026-05-23 20:26:59 +02:00
parent 42e3571fab
commit a264336bd8
14 changed files with 339 additions and 48 deletions
+2 -6
View File
@@ -978,10 +978,6 @@ export type MarketListSchema = {
* Description
*/
description: string;
/**
* Type
*/
type: string;
/**
* Status
*/
@@ -1014,9 +1010,9 @@ export type MarketOptionSchema = {
*/
text: string;
/**
* Position
* Total Bets
*/
position: number;
total_bets?: number;
};
/**
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { polylanSubmitterApiGetUserInfo, marketApiCreateBet, marketApiListUserBets } from "../api";
import type { Market } from "../types";
import type { Market, MarketOption } from "../types";
import type { UserInfoOut, UserBetSchema } from "../api/types.gen";
const props = defineProps<{
@@ -53,6 +53,21 @@ const canBet = computed(() => {
return props.market.status === "open" && userInfo.value?.is_authenticated && selectedOption.value && betAmount.value > 0;
});
const totalPot = computed(() => {
return props.market.options.reduce((sum, opt) => sum + opt.total_bets, 0);
});
const getMultiplier = (option: MarketOption) => {
if (option.total_bets === 0) return 0;
return totalPot.value / option.total_bets;
};
const getPotentialGain = (option: MarketOption) => {
if (!existingBet.value || existingBet.value.option.uuid !== option.uuid) return 0;
const multiplier = getMultiplier(option);
return Math.round(existingBet.value.amount * multiplier);
};
const placeBet = async () => {
if (!selectedOption.value || !betAmount.value) return;
@@ -75,7 +90,14 @@ const placeBet = async () => {
await loadUserBets();
betAmount.value = 0;
} else {
error.value = String(response.error) || "Failed to place bet";
const err = response.error as any;
if (typeof err === 'object' && err?.detail) {
error.value = err.detail;
} else if (typeof err === 'string') {
error.value = err;
} else {
error.value = "Failed to place bet";
}
}
} catch (e) {
error.value = "Error placing bet";
@@ -145,10 +167,18 @@ onMounted(async () => {
]">
<div class="flex flex-col gap-2 flex-1">
<span class="label-text font-medium">{{ option.text }}</span>
<span v-if="existingBet && existingBet.option.uuid === option.uuid"
class="badge badge-primary badge-sm w-fit">
Your bet: {{ existingBet.amount }} pts
</span>
<div class="text-xs text-base-content/60">
<div>Pool: {{ option.total_bets }} pts</div>
<div v-if="option.total_bets > 0">Multiplier: {{ getMultiplier(option).toFixed(2) }}x</div>
</div>
<div v-if="existingBet && existingBet.option.uuid === option.uuid" class="flex flex-col gap-1">
<span class="badge badge-primary badge-sm w-fit">
Your bet: {{ existingBet.amount }} pts
</span>
<span v-if="option.total_bets > 0" class="badge badge-success badge-sm w-fit">
Potential: {{ getPotentialGain(option) }} pts
</span>
</div>
</div>
<input type="radio" :value="option.uuid" v-model="selectedOption" class="radio radio-primary"
:disabled="market.status !== 'open' || !!(existingBet && existingBet.option.uuid !== option.uuid)" />
+1 -2
View File
@@ -173,14 +173,13 @@ export interface TournamentPuzzleResults {
export interface MarketOption {
uuid: string
text: string
position: number
total_bets: number
}
export interface Market {
uuid: string
title: string
description: string
type: 'yes_no' | 'multiple'
status: 'open' | 'closed' | 'resolved'
end_date: string
created_at: string