Skip to content

Commit

Permalink
Merge pull request #15 from sergio222-dev/develop
Browse files Browse the repository at this point in the history
added budget calculator
  • Loading branch information
sergio222-dev authored Aug 11, 2024
2 parents 223ccfd + e47d748 commit 80dee10
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 16 deletions.
48 changes: 42 additions & 6 deletions src/features/createDeck/components/CardDeckInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { component$, useComputed$, useContext } from '@builder.io/qwik';
import { CardDeckControl } from '~/features/createDeck/components/CardDeckControl';
import { CARD_TYPES } from '~/models/CardTypes';
import { DeckCreationContext } from '~/stores/deckCreationContext';
import { DeckCreationContext } from '~/stores/deckCreationContext';
import { costCalculator, getColorLever } from "~/utils/costCalculator";

export const CardDeckInfo = component$(() => {
const d = useContext(DeckCreationContext);
Expand All @@ -21,49 +22,84 @@ export const CardDeckInfo = component$(() => {
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const unitCardsQuantity = useComputed$(() => {
return orderedUnitCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedActionCards = useComputed$(() => {
return Object.entries(deckData.masterDeck)
.map(([, c]) => c)
.filter(c => c.type === CARD_TYPES.ACTION)
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const actionCardsQuantity = useComputed$(() => {
return orderedActionCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedTreasureCards = useComputed$(() => {
return Object.entries(deckData.treasureDeck)
.map(([, c]) => c)
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const treasureCardsQuantity = useComputed$(() => {
return orderedTreasureCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedMonumentCards = useComputed$(() => {
return Object.entries(deckData.masterDeck)
.map(([, c]) => c)
.filter(c => c.type === CARD_TYPES.MONUMENTO)
.toSorted((a, b) => a.name.localeCompare(b.name))
});

const monumentCardsQuantity = useComputed$(() => {
return orderedMonumentCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedSideCards = useComputed$(() => {
return Object.entries(deckData.sideDeck)
.map(([, c]) => c)
.toSorted((a, b) => a.name.localeCompare(b.name))
});

const sideCardsQuantity = useComputed$(() => {
return orderedSideCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const costLevelDeck = useComputed$(() => {
const allCards = {
...deckData.masterDeck,
...deckData.treasureDeck,
...deckData.sideDeck
};

return costCalculator(allCards);
})

const colorLevelDeck = useComputed$(() => {
return getColorLever(costLevelDeck.value);
});

return (
<div class="p-4 shadow-lg m-4">
<div>Presupuesto: <span style={{ color: colorLevelDeck.value }}> {costLevelDeck.value}</span></div>
<div class="flex justify-center">
<p class="text-center">Total number of cards in deck:<br/>{deckTotalCards.value}</p>
</div>

<div class="p-4 grid md:grid-cols-2 gap-4">
<div>
<p class="text-center">Unidades</p>
<p class="text-center">Unidades ({unitCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedUnitCards.value.map(c => (
<CardDeckControl key={c.id} card={c}/>
))}
</div>
</div>
<div>
<p class="text-center">Acciones</p>
<p class="text-center">Acciones ({actionCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedActionCards.value.map(c => (
<CardDeckControl key={c.id} card={c}/>
Expand All @@ -74,7 +110,7 @@ export const CardDeckInfo = component$(() => {

{orderedMonumentCards.value.length > 0 &&
<div class="p-4">
<p class="text-center">Monumentos</p>
<p class="text-center">Monumentos ({monumentCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedMonumentCards.value.map(c => (
<CardDeckControl orientation="horizontal" key={c.id} card={c}/>
Expand All @@ -84,7 +120,7 @@ export const CardDeckInfo = component$(() => {
}

<div class="p-4">
<p class="text-center">Tesoros</p>
<p class="text-center">Tesoros ({treasureCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedTreasureCards.value.map(c => (
<CardDeckControl orientation="horizontal" key={c.id} card={c}/>
Expand All @@ -94,7 +130,7 @@ export const CardDeckInfo = component$(() => {

{orderedSideCards.value.length > 0 &&
<div class="p-4">
<p class="text-center">Side</p>
<p class="text-center">Side ({sideCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedSideCards.value.map(c => (
<CardDeckControl orientation="horizontal" isSide key={c.id} card={c}/>
Expand Down
26 changes: 22 additions & 4 deletions src/features/preview/Preview.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import { component$ } from "@builder.io/qwik";
import { CardDeckInfoPreview } from "~/features/preview/components/CardDeckInfoPreview";
import { usePublicDeckLoader } from "~/providers/loaders/decks";
import { component$, useComputed$ } from "@builder.io/qwik";
import { CardDeckInfoPreview } from "~/features/preview/components/CardDeckInfoPreview";
import { usePublicDeckLoader } from "~/providers/loaders/decks";
import { costCalculator, getColorLever } from "~/utils/costCalculator";

export const PreviewDeck = component$(() => {
const deck = usePublicDeckLoader();

const costLevelDeck = useComputed$(() => {
const allCards = {
...deck.value?.masterDeck,
...deck.value?.treasureDeck,
...deck.value?.sideDeck
};

return costCalculator(allCards);
})

const colorLevelDeck = useComputed$(() => {
return getColorLever(costLevelDeck.value);
});

return (
<div>
{!deck.value && <div>Loading...</div>}
Deck Name: {deck.value?.name}
<div class="flex flex-col items-center justify-center">
<h1 class="text-3xl">{deck.value?.name}</h1>
<p>Presupuesto: <span style={{ color: colorLevelDeck.value }}> {costLevelDeck.value}</span></p>
</div>

{deck.value && <CardDeckInfoPreview deck={deck.value}/>}
</div>
Expand Down
32 changes: 26 additions & 6 deletions src/features/preview/components/CardDeckInfoPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,69 @@ export const CardDeckInfoPreview = component$<CardDeckInfoProps>(({ deck }) => {
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const unitCardsQuantity = useComputed$(() => {
return orderedUnitCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedActionCards = useComputed$(() => {
return Object.entries(deck.masterDeck)
.map(([, c]) => c)
.filter(c => c.type === CARD_TYPES.ACTION)
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const actionCardsQuantity = useComputed$(() => {
return orderedActionCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedTreasureCards = useComputed$(() => {
return Object.entries(deck.treasureDeck)
.map(([, c]) => c)
.toSorted((a, b) => a.name.localeCompare(b.name));
});

const treasureCardsQuantity = useComputed$(() => {
return orderedTreasureCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedMonumentCards = useComputed$(() => {
return Object.entries(deck.masterDeck)
.map(([, c]) => c)
.filter(c => c.type === CARD_TYPES.MONUMENTO)
.toSorted((a, b) => a.name.localeCompare(b.name))
});

const monumentCardsQuantity = useComputed$(() => {
return orderedMonumentCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

const orderedSideCards = useComputed$(() => {
return Object.entries(deck.sideDeck)
.map(([, c]) => c)
.toSorted((a, b) => a.name.localeCompare(b.name))
});

const sideCardsQuantity = useComputed$(() => {
return orderedSideCards.value.reduce((acc, c) => acc + c.quantity, 0);
});

return (
<div class="p-4 shadow-lg m-4">
<div class="flex justify-center">
<div class="flex justify-center gap-4">
<p class="text-center">Total number of cards in deck:<br/>{deckTotalCards.value}</p>
</div>

<div class="p-4 grid md:grid-cols-2 gap-4">
<div>
<p class="text-center">Unidades</p>
<p class="text-center">Unidades ({unitCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedUnitCards.value.map(c => (
<CardDeckControlPreview key={c.id} card={c} deck={deck}/>
))}
</div>
</div>
<div>
<p class="text-center">Acciones</p>
<p class="text-center">Acciones ({actionCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedActionCards.value.map(c => (
<CardDeckControlPreview key={c.id} card={c} deck={deck}/>
Expand All @@ -75,7 +95,7 @@ export const CardDeckInfoPreview = component$<CardDeckInfoProps>(({ deck }) => {

{orderedMonumentCards.value.length > 0 &&
<div class="p-4">
<p class="text-center">Monumentos</p>
<p class="text-center">Monumentos ({monumentCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedMonumentCards.value.map(c => (
<CardDeckControlPreview orientation="horizontal" key={c.id} card={c} deck={deck}/>
Expand All @@ -84,7 +104,7 @@ export const CardDeckInfoPreview = component$<CardDeckInfoProps>(({ deck }) => {
</div>
}
<div class="p-4">
<p class="text-center">Tesoros</p>
<p class="text-center">Tesoros ({treasureCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedTreasureCards.value.map(c => (
<CardDeckControlPreview orientation="horizontal" key={c.id} card={c} deck={deck}/>
Expand All @@ -94,7 +114,7 @@ export const CardDeckInfoPreview = component$<CardDeckInfoProps>(({ deck }) => {

{orderedSideCards.value.length > 0 &&
<div class="p-4">
<p class="text-center">Side</p>
<p class="text-center">Side ({sideCardsQuantity})</p>
<div class="flex flex-wrap">
{orderedSideCards.value.map(c => (
<CardDeckControlPreview orientation="horizontal" isSide key={c.id} card={c} deck={deck}/>
Expand Down
1 change: 1 addition & 0 deletions src/models/Deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { NormalizedModel } from "~/utils/normalize";

export interface DeckCard extends Card {
quantity: number;
rarity: string;
}

export interface DeckItem {
Expand Down
90 changes: 90 additions & 0 deletions src/utils/costCalculator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { DeckCard } from "~/models/Deck";
import type { NormalizedModel } from "~/utils/normalize";

const COST_LEVELS = {
BASIC: 'Basico',
AFFORDABLE: 'Accesible',
ECONOMICAL: 'Ecnómico',
INTERMEDIATE: 'Intermedio',
ADVANCED: 'Avanzado',
COMPETITIVE: 'Competitivo',
PREMIUM: 'Premium',
EXCLUSIVE: 'Exclusivo',
}

const COST_LEVEL_BREAKPOINTS = 158;

function getCostPoints(rarity: string): number {
switch (rarity) {
case 'BRONCE':
return 1;
case 'PLATA':
return 4;
case 'ORO':
return 16;
case 'DIAMANTE':
return 64;
case 'ESMERALDA':
return 128;
default:
return 0;
}
}

// pass as parameter one value from the COST_LEVELS object
export function getColorLever(level: typeof COST_LEVELS[keyof typeof COST_LEVELS]) {
// get the index of the level
const index = Object.values(COST_LEVELS).indexOf(level);
// get the color from the index
// Asegúrate de que el nivel esté dentro del rango 1-8

// Calcula la proporción de nivel (0 para verde y 1 para rojo)
const ratio = (index) / 7;

// Calcula los componentes RGB
const r = Math.round(255 * ratio);
const g = Math.round(255 * (1 - ratio));
const b = 0; // Mantén el azul en 0 para la transición entre verde y rojo

// Devuelve el color en formato hexadecimal
return `rgb(${r},${g},${b})`;
}


export function costCalculator(cards: NormalizedModel<DeckCard>): typeof COST_LEVELS[keyof typeof COST_LEVELS] {
const costPoints = Object.values(cards).reduce((acc, c) => acc + getCostPoints(c.rarity) * c.quantity, 0);

if (costPoints < COST_LEVEL_BREAKPOINTS) {
return COST_LEVELS.BASIC;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 2) {
return COST_LEVELS.AFFORDABLE;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 3) {
return COST_LEVELS.ECONOMICAL;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 4) {
return COST_LEVELS.INTERMEDIATE;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 5) {
return COST_LEVELS.ADVANCED;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 6) {
return COST_LEVELS.COMPETITIVE;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 7) {
return COST_LEVELS.PREMIUM;
}

if (costPoints < COST_LEVEL_BREAKPOINTS * 8) {
return COST_LEVELS.EXCLUSIVE;
}

return COST_LEVELS.PREMIUM;
}

0 comments on commit 80dee10

Please sign in to comment.