diff --git a/.env b/.env index b99dca87..b62b5529 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -DECO_SITE_NAME=starting \ No newline at end of file +DECO_SITE_NAME=starting +DECO_ENV_NAME=estrangeiro \ No newline at end of file diff --git a/fresh.gen.ts b/fresh.gen.ts index 3fb32afb..e5a83c5f 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -53,6 +53,7 @@ import * as $NRF_TextLines from "./islands/NRF/TextLines.tsx"; import * as $OnThisPage from "./islands/OnThisPage.tsx"; import * as $PopUp from "./islands/PopUp.tsx"; import * as $PopularDocuments from "./islands/PopularDocuments.tsx"; +import * as $PriceCalculatorIsland from "./islands/PriceCalculatorIsland.tsx"; import * as $Projects from "./islands/Projects.tsx"; import * as $RankingAnalyze from "./islands/RankingAnalyze.tsx"; import * as $RankingHeader from "./islands/RankingHeader.tsx"; @@ -123,6 +124,7 @@ const manifest = { "./islands/OnThisPage.tsx": $OnThisPage, "./islands/PopUp.tsx": $PopUp, "./islands/PopularDocuments.tsx": $PopularDocuments, + "./islands/PriceCalculatorIsland.tsx": $PriceCalculatorIsland, "./islands/Projects.tsx": $Projects, "./islands/RankingAnalyze.tsx": $RankingAnalyze, "./islands/RankingHeader.tsx": $RankingHeader, diff --git a/islands/PriceCalculatorIsland.tsx b/islands/PriceCalculatorIsland.tsx new file mode 100644 index 00000000..460c90aa --- /dev/null +++ b/islands/PriceCalculatorIsland.tsx @@ -0,0 +1,660 @@ +import { useState, useEffect } from "preact/hooks"; + +interface INPUT { + plan: string; + hosting: string; + builder_seats: number; + content_editor_seats: number; + general_seats: number; + infrastructure: string; + pageviews: number; + support: string; +} + +export default function PriceCalculatorIsland() { + const [inputs, setInputs] = useState({ + currency: "BRL", + plan: "enterprise", + hosting: "cloud", + builder_seats: 0, + content_editor_seats: 0, + general_seats: 0, + infrastructure: "efficient", + pageviews: 0, + support: "free", + }); + + const [estimatedCost, setEstimatedCost] = useState({ + infrastructure: { + total: 0, + bandwidth: 0, + request: 0, + }, + efficiency: { + not_optimized: 0, + efficient: 0, + medium_efficiency: 0, + }, + seats: 0, + support: 0, + total: 0, + }); + + function updateCosts() { + const infrastructureCost = calculateInfrastructure(inputs); + const { total, bandwidth, request } = + infrastructureCost.selectedInfrastructure || + { total: 0, bandwidth: 0, request: 0 }; + const seatsCost = calculateSeats(inputs); + const supportCost = calculateSupport(inputs); + + const totalCost = seatsCost + total + supportCost; + + const updatedCost = { + ...estimatedCost, + infrastructure: { + total, + bandwidth, + request, + }, + efficiency: { + not_optimized: + infrastructureCost.otherInfrastructures.not_optimized.total, + efficient: infrastructureCost.otherInfrastructures.efficient.total, + medium_efficiency: + infrastructureCost.otherInfrastructures.medium_efficiency.total, + }, + seats: seatsCost, + support: supportCost, + total: totalCost, + }; + setEstimatedCost(updatedCost); + } + + useEffect(() => { + updateCosts(); + }, [inputs]); + + // Reusable input style + const inputStyle = + "w-full bg-black border border-gray-700 rounded-md p-2 text-white focus:border-emerald-400 focus:outline-none focus:ring-1 focus:ring-emerald-400"; + + return ( +
+
+
+

+ Calculadora de preços deco.cx +

+
+
+ {/* Left Column - Configurations */} +
+

Configurações

+ +
+ {/* Currency Selection */} +
+ + +
+ + {/* Plans */} +
+ +

+ Não sabe qual é para você? Veja os{" "} + + recursos incluídos + {" "} + em cada plano. +

+
+ + +
+
+ +
+ {/* License Inputs */} +
+
+ +

+ Acesso irrestrito para desenvolver e orquestrar +

+ { + setInputs({ + ...inputs, + builder_seats: value.currentTarget.valueAsNumber, + }); + updateCosts(); + }} + /> +
+
+ +

+ Acesso para editar conteúdos e utilizar dados +

+ { + setInputs({ + ...inputs, + content_editor_seats: + event.currentTarget.valueAsNumber, + }); + updateCosts(); + }} + /> +
+
+
+ +
+
+ +

+ Acesso para editar conteúdos e utilizar dados +

+ { + setInputs({ + ...inputs, + general_seats: event.currentTarget.valueAsNumber, + }); + updateCosts(); + }} + /> +
+
+ + {/* Infrastructure */} +
+ +

+ Escolha entre infra 100% gerenciada ou hospede projetos você + mesmo. +

+
+ + +
+
+ + {/* Pageviews */} +
+ +

+ Para calcular multiplique sessões por média de páginas + visitadas / sessão +

+ { + setInputs({ + ...inputs, + pageviews: event.currentTarget.valueAsNumber, + }); + updateCosts(); + }} + /> +

+ Nota: Embora o custo agora seja calculado com base em + requisições e consumo de banda, pedimos a média de pageviews + mensais porque é mais fácil de estimar, especialmente para + novos clientes. Usaremos esse número como uma referência para + simulações e projeções de custos. +

+
+ + {/* Support Packages */} +
+ +

+ Não sabe qual é para você? Veja os{" "} + + recursos incluídos + {" "} + em cada pacote. +

+
+ + + +
+
+
+
+ + {/* Right Column - Estimated Costs */} +
+

Custos estimados

+ +
+ {/* License Cost */} +
+ Licenciamento de seats + + {formatToReal(estimatedCost.seats)} + +
+ + {/* Infrastructure */} +
+
+ Infraestrutura +
+ + {formatToReal(estimatedCost.infrastructure.total)} + +
+
+ + Fale com o nosso time de vendas + +
+
+ +
+
+ + + +
+ +
+ Banda + + {formatToReal(estimatedCost.infrastructure.bandwidth)} + +
+ +
+ Request + + {formatToReal(estimatedCost.infrastructure.request)} + +
+
+
+ + {/* Support */} +
+ Suporte + + {formatToReal(estimatedCost.support)} + +
+ + {/* Total Cost */} +
+
+ Custo Mensal Total + + {formatToReal(estimatedCost.total)} + +
+
+
+ + {/* Infrastructure Efficiency Scenarios */} +
+

+ Cenários de eficiência da infraestrutura +

+
+
+
+ Eficiente + +
+ + {formatToReal(estimatedCost.efficiency.efficient)} + +
+
+
+ Eficiência média + +
+ + {formatToReal(estimatedCost.efficiency.medium_efficiency)} + +
+
+
+ Não otimizado + +
+ + {formatToReal(estimatedCost.efficiency.not_optimized)} + +
+
+
+
+
+
+
+ ); +} + +const EFFICIENTY_COSTS = { + not_optimized: { + bandwidth: 1.0405, + request: 10.119375, + }, + medium_efficiency: { + bandwidth: 0.7, + request: 8.601192, + }, + efficient: { + bandwidth: 0.25, + request: 6.977226, + }, +}; + +function calculateSeats(inputs: INPUT) { + const { plan, builder_seats, content_editor_seats, general_seats } = inputs; + + let seats = 0; + + if (plan === "enterprise") { + /// Builder + if (builder_seats > 100) { + seats += builder_seats * 250; + } else if (builder_seats > 50) { + seats += 25000; + } else if (builder_seats > 20) { + seats += 15000; + } else if (builder_seats > 10) { + seats += 7000; + } else if (builder_seats > 5) { + seats += 4000; + } else if (builder_seats > 1) { + seats += 2250; + } else if (builder_seats === 1) { + seats += 500; + } + + /// Content Editor + if (content_editor_seats > 100) { + seats += content_editor_seats * 125; + } else if (content_editor_seats > 50) { + seats += 12500; + } else if (content_editor_seats > 20) { + seats += 7500; + } else if (content_editor_seats > 10) { + seats += 3500; + } else if (content_editor_seats > 5) { + seats += 2000; + } else if (content_editor_seats > 1) { + seats += 1125; + } else if (content_editor_seats === 1) { + seats += 250; + } + } else { + if (general_seats > 100) { + seats += 30 * general_seats; + } else if (general_seats > 50) { + seats += 3000; + } else if (general_seats > 20) { + seats += 1750; + } else if (general_seats > 10) { + seats += 800; + } else if (general_seats > 5) { + seats += 450; + } else if (general_seats > 1) { + seats += 250; + } else if (general_seats === 1) { + seats += 55; + } + } + + return seats; +} + +function calculateInfrastructure(inputs: INPUT) { + let { pageviews, infrastructure, hosting } = inputs; + + if (isNaN(pageviews)) { + pageviews = 0; + } + + const result = { + not_optimized: calculateScenario(pageviews, "not_optimized"), + medium_efficiency: calculateScenario(pageviews, "medium_efficiency"), + efficient: calculateScenario(pageviews, "efficient"), + }; + + const selectedInfrastructure = (hosting === "self") + ? { total: 0, bandwidth: 0, request: 0 } + : result[infrastructure]; + + return { + selectedInfrastructure, + otherInfrastructures: result, + }; +} + +function calculateScenario(pageviews: number, infrastructureType: string) { + const { bandwidth: bandwidthCost, request: requestCost } = + EFFICIENTY_COSTS[infrastructureType]; + + const bandwidth = pageviews * bandwidthCost; + const request = pageviews * requestCost * 0.0004; + const total = bandwidth + request; + + return { total, bandwidth, request }; +} + +function calculateSupport(input: INPUT) { + const support = input.support; + + let cost = 0; + + switch (support) { + case "free": + cost = 0; + break; + case "premium": + cost = 5000; + break; + case "enterprise": + cost = 10000; + break; + } + + return cost; +} + +function formatToReal(value: number) { + return value.toLocaleString("pt-BR", { + style: "currency", + currency: "BRL", + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); +} diff --git a/sections/priceCalculator.tsx b/sections/priceCalculator.tsx index 40ac0f5b..97ce60fb 100644 --- a/sections/priceCalculator.tsx +++ b/sections/priceCalculator.tsx @@ -1,14 +1,5 @@ -interface Props { - /** - * @description The description of name. - */ - calculatorHTML: string; -} +import PriceCalculatorIsland from "site/islands/PriceCalculatorIsland.tsx"; -export default function Section({ calculatorHTML }: Props) { - return ( -
-
-
- ) +export default function Section() { + return ; } \ No newline at end of file diff --git a/static/tailwind.css b/static/tailwind.css index e6500a35..3e8a363d 100644 --- a/static/tailwind.css +++ b/static/tailwind.css @@ -8865,6 +8865,11 @@ details.collapse summary::-webkit-details-marker { margin-right: calc(0.75rem * var(--tw-space-x-reverse)); margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); } +.space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} .space-x-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.5rem * var(--tw-space-x-reverse)); @@ -9361,6 +9366,10 @@ details.collapse summary::-webkit-details-marker { --tw-border-opacity: 1; border-color: rgb(10 33 33 / var(--tw-border-opacity)); } +.border-emerald-400 { + --tw-border-opacity: 1; + border-color: rgb(52 211 153 / var(--tw-border-opacity)); +} .border-gray-200 { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); @@ -9373,6 +9382,10 @@ details.collapse summary::-webkit-details-marker { --tw-border-opacity: 1; border-color: rgb(156 163 175 / var(--tw-border-opacity)); } +.border-gray-700 { + --tw-border-opacity: 1; + border-color: rgb(55 65 81 / var(--tw-border-opacity)); +} .border-gray-800 { --tw-border-opacity: 1; border-color: rgb(31 41 55 / var(--tw-border-opacity)); @@ -9711,6 +9724,9 @@ details.collapse summary::-webkit-details-marker { --tw-bg-opacity: 1; background-color: rgb(218 143 255 / var(--tw-bg-opacity)); } +.bg-emerald-400\/10 { + background-color: rgb(52 211 153 / 0.1); +} .bg-gray-100 { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); @@ -10509,6 +10525,9 @@ details.collapse summary::-webkit-details-marker { .font-inter { font-family: Inter, sans-serif; } +.font-mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} .font-sans { font-family: Albert Sans, sans-serif; } @@ -10967,6 +10986,9 @@ details.collapse summary::-webkit-details-marker { .tracking-wide { letter-spacing: 0.025em; } +.tracking-wider { + letter-spacing: 0.05em; +} .\!text-\[\#F9FAFB\] { --tw-text-opacity: 1 !important; color: rgb(249 250 251 / var(--tw-text-opacity)) !important; @@ -11229,6 +11251,10 @@ details.collapse summary::-webkit-details-marker { --tw-text-opacity: 1; color: rgb(2 246 124 / var(--tw-text-opacity)); } +.text-emerald-400 { + --tw-text-opacity: 1; + color: rgb(52 211 153 / var(--tw-text-opacity)); +} .text-frame-515-rgba { color: rgba(31, 38, 31, 0.67); } @@ -11396,6 +11422,9 @@ details.collapse summary::-webkit-details-marker { --tw-placeholder-opacity: 1; color: rgb(255 255 255 / var(--tw-placeholder-opacity)); } +.accent-emerald-400 { + accent-color: #34d399; +} .opacity-0 { opacity: 0; } @@ -12718,11 +12747,27 @@ select.light-autofill:-webkit-autofill:focus { border-color: rgb(0 0 0 / var(--tw-border-opacity)); } +.focus\:border-emerald-400:focus { + --tw-border-opacity: 1; + border-color: rgb(52 211 153 / var(--tw-border-opacity)); +} + .focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; } +.focus\:ring-1:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-emerald-400:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(52 211 153 / var(--tw-ring-opacity)); +} + .focus\:ring-indigo-500:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));