view update

This commit is contained in:
Dominic Ferrando
2025-09-18 18:43:19 -04:00
parent c3c347cf9f
commit 5133379b9c
27 changed files with 112 additions and 147 deletions
-88
View File
@@ -1,88 +0,0 @@
import { Elysia } from "elysia";
import { cors } from "@elysiajs/cors";
import { ActivityStandards, LevelCalculator, Standards } from "./services/calculator/main";
import { ActivityPerformance, Player } from "./services/calculator/util";
import { Printful } from "./services/commerce/printful";
import { Webflow } from "./services/commerce/webflow";
import rawStandards from "./data/standards.json" assert { type: "json" }
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
export const app = new Elysia({ prefix: "/api" })
.use(cors())
.get("/", () => "Hello world")
// CALCULATOR
.post("/calculate", async ({ body }) => {
const MAIN_STANDARDS = new Standards(rawStandards as ActivityStandards);
interface CalcRequest {
player: Player;
activityPerformances: ActivityPerformance[];
}
const { player, activityPerformances } = body as CalcRequest;
const levelCalculator = new LevelCalculator(MAIN_STANDARDS);
return { levels: levelCalculator.calculate(player, activityPerformances) };
})
// COMMERCE
.post("/products/sync", async () => {
const printfulProducts = await Printful.Products.getAll();
for (const p of printfulProducts) {
const exists = await Webflow.Products.exists(p.sync_product.external_id);
if (exists) await Webflow.Products.updateUsingPrintful(p);
else await Webflow.Products.createUsingPrintful(p);
}
return {};
})
// DATA
.get("/data/standards", async () => {
try {
return Bun.file(join(__dirname, "data/standards.json")).json();
} catch (error) {
console.error(error);
return new Response("Failed to load standards", { status: 500 });
}
})
// WEBHOOKS
.post("/webhook/printful", async ({ body, set }) => {
const payload = body as Printful.Webhook.EventPayload;
try {
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const prod = await Printful.Products.get(payload.data.sync_product.id);
const exists = await Webflow.Products.exists(prod.sync_product.external_id);
if (exists) await Webflow.Products.updateUsingPrintful(prod);
else await Webflow.Products.createUsingPrintful(prod);
break;
}
case Printful.Webhook.Event.ProductDeleted: {
await Webflow.Products.remove(payload.data.sync_product.external_id);
break;
}
}
} catch (error) {
console.error(error);
set.status = 500;
return { error: "internal_error" };
}
return "";
});
if (import.meta.main) {
app.listen(3000);
console.log(
`Listening at ${app.server?.hostname}:${app.server?.port}`,
);
}
export type App = typeof app;
View File
-5
View File
@@ -1,5 +0,0 @@
CREATE TABLE IF NOT EXISTS product_records (
webflowProductId INTEGER NOT NULL,
printfulProductId INTEGER NOT NULL,
UNIQUE(webflowProductId, printfulProductId)
)
+72
View File
@@ -0,0 +1,72 @@
import { treaty } from "@elysiajs/eden";
import { Elysia } from "elysia";
import { cors } from "@elysiajs/cors";
import { LevelCalculator, Standards, type ActivityStandards } from "$lib/services/calculator/main";
import type { ActivityPerformance, Player } from "$lib/services/calculator/util";
import { Webflow } from "$lib/services/commerce/webflow";
import { Printful } from "$lib/services/commerce/printful";
import rawStandards from "$lib/data/standards.json" assert { type: "json" }
export const app = new Elysia({ prefix: "/api" })
.use(cors({
origin: '*'
}))
.get("/", () => "Hello world")
// CALCULATOR
.post("/calculate", async ({ body }) => {
const MAIN_STANDARDS = new Standards(rawStandards as ActivityStandards);
interface CalcRequest {
player: Player;
activityPerformances: ActivityPerformance[];
}
const { player, activityPerformances } = body as CalcRequest;
const levelCalculator = new LevelCalculator(MAIN_STANDARDS);
return { levels: levelCalculator.calculate(player, activityPerformances) };
})
// COMMERCE
.post("/products/sync", async () => {
const printfulProducts = await Printful.Products.getAll();
for (const p of printfulProducts) {
const exists = await Webflow.Products.exists(p.sync_product.external_id);
if (exists) await Webflow.Products.updateUsingPrintful(p);
else await Webflow.Products.createUsingPrintful(p);
}
return {};
})
// WEBHOOKS
.post("/webhook/printful", async ({ body, set }) => {
const payload = body as Printful.Webhook.EventPayload;
try {
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const prod = await Printful.Products.get(payload.data.sync_product.id);
const exists = await Webflow.Products.exists(prod.sync_product.external_id);
if (exists) await Webflow.Products.updateUsingPrintful(prod);
else await Webflow.Products.createUsingPrintful(prod);
break;
}
case Printful.Webhook.Event.ProductDeleted: {
await Webflow.Products.remove(payload.data.sync_product.external_id);
break;
}
}
} catch (error) {
console.error(error);
set.status = 500;
return { error: "internal_error" };
}
return "";
});
export type App = typeof app;
const apiWrapper = treaty<App>(app);
export const api = apiWrapper.api;

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,4 +1,4 @@
import { Activity, Attribute, Player, Gender, ActivityPerformance, lbToKg, StandardUnit } from "./util";
import { Activity, Attribute, Gender, lbToKg, type ActivityPerformance, type Player, type StandardUnit } from "./util";
// SOURCES
// Squat, Bench, Dead Lift:
@@ -434,7 +434,7 @@ export class Standards {
return levels;
}
const newLevels = {};
const newLevels: Levels = {};
let j = 1;
for (let k = 0; k < Object.keys(levels).length; ++k) {
const currLevel = Object.keys(levels)[k];
@@ -489,7 +489,7 @@ export class Standards {
const lerp = (lvl: string) => (lower[lvl] as number) + ((upper[lvl] as number) - (lower[lvl] as number)) * ratio;
const interpolatedLevels = {};
const interpolatedLevels: Levels = {};
for (const lvl in lower) {
interpolatedLevels[lvl] = lerp(lvl);
}
@@ -1,4 +1,4 @@
import { Metrics } from "../calculator/main";
import { type Metrics } from "$lib/services/calculator/main";
// -------------------------------------------------------------------------------------------------
// DATA MODELS
@@ -1,4 +1,4 @@
import { Printful } from "./printful"
import { Printful } from "$lib/services/commerce/printful"
export namespace Webflow {
export const API_SITES_URL = `https://api.webflow.com/v2/sites/${Bun.env.WEBFLOW_SITE_ID}`;
@@ -1,6 +1,4 @@
import { Activity, ActivityPerformance, feetToCm, Gender, inchesToCm, lbToKg, minToMs, Player, secToMs } from "../services/calculator/util";
import { ActivityStandards, LevelCalculator, Standards } from "../services/calculator/main"
import rawStandards from "../data/standards.json" assert { type: "json" }
import { Activity, feetToCm, Gender, inchesToCm, lbToKg, minToMs, secToMs, type ActivityPerformance, type Player } from "$lib/services/calculator/util";
const player: Player = {
metrics: {
@@ -41,6 +39,8 @@ const computedPerformances: ActivityPerformance[] = [
},
];
const standards = new Stand();
// const newStandards: Standards = {
// "Back Squat": [],
// "Deadlift": [],
@@ -1,8 +1,10 @@
<script lang="ts">
import {
Standards,
type ActivityStandards,
type Standard,
} from "../../../services/calculator/main";
} from "$lib/services/calculator/main";
import allStandardsRaw from "$lib/data/standards.json" assert { type: "json" };
import {
Activity,
Gender,
@@ -10,10 +12,7 @@
lbToKg,
msToTime,
range,
} from "../../../services/calculator/util";
// data
const { data } = $props();
} from "$lib/services/calculator/util";
const selected = $state({
activity: Activity.BenchPress,
@@ -24,7 +23,9 @@
});
const allStandards = $derived(
new Standards(data.allStandardsRaw, { maxLevel: selected.maxLevel }),
new Standards(allStandardsRaw as ActivityStandards, {
maxLevel: selected.maxLevel,
}),
);
const getFormattedLevelValue = (
@@ -1,4 +1,4 @@
import { app } from "../../../../api"
import { app } from "$lib/api"
type RequestHandler = (v: { request: Request }) => Response | Promise<Response>
export const fallback: RequestHandler = ({ request }) => app.handle(request)
-6
View File
@@ -1,6 +0,0 @@
import { treaty } from "@elysiajs/eden";
import { app, type App } from "../../../api";
const apiWrapper = treaty<App>(app);
export const api = apiWrapper.api;
-11
View File
@@ -1,11 +0,0 @@
import { api } from "$lib";
import type { ActivityStandards } from "../../../services/calculator/main";
import type { LayoutServerLoad } from "./$types";
export const load: LayoutServerLoad = async ({ }) => {
const { data: allStandardsRaw } = await api.data.standards.get();
return {
allStandardsRaw: allStandardsRaw as ActivityStandards
};
};
-3
View File
@@ -1,3 +0,0 @@
# allow crawling everything by default
User-agent: *
Disallow:
-18
View File
@@ -1,18 +0,0 @@
import adapter from "svelte-adapter-bun";
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter(),
}
};
export default config;
-20
View File
@@ -1,20 +0,0 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// To make changes to top-level options such as include and exclude, we recommend extending
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
}
-6
View File
@@ -1,6 +0,0 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});