feat: implement logging functionality and improve API endpoint handling in backend; refactor frontend to use dynamic API base
All checks were successful
Build and publish Docker image / build-and-push (release) Successful in 14s
All checks were successful
Build and publish Docker image / build-and-push (release) Successful in 14s
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { onMount } from "svelte";
|
||||
import CounterCard from "./CounterCard.svelte";
|
||||
import AddCounterCard from "./AddCounterCard.svelte";
|
||||
import { API_COUNTERS } from "./config";
|
||||
|
||||
type Counter = {
|
||||
id: number;
|
||||
@@ -13,19 +14,17 @@
|
||||
let counters: Counter[] = [];
|
||||
let loading = true;
|
||||
|
||||
// API endpoint
|
||||
const API = "http://localhost:3000/api/counters";
|
||||
// Use a relative API base so it works no matter the host/origin
|
||||
const API = API_COUNTERS;
|
||||
const CACHE_KEY = "tally-counters-cache";
|
||||
|
||||
async function fetchCounters() {
|
||||
loading = true;
|
||||
// Try to load from cache first
|
||||
const cached = localStorage.getItem(CACHE_KEY);
|
||||
if (cached) {
|
||||
counters = JSON.parse(cached);
|
||||
loading = false;
|
||||
}
|
||||
// Always fetch fresh data in the background
|
||||
const res = await fetch(API);
|
||||
const fresh = await res.json();
|
||||
counters = fresh;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { clickOutside } from "./clickOutside";
|
||||
import { API_BASE } from "./config";
|
||||
import { onDestroy } from 'svelte';
|
||||
|
||||
export let counter: {
|
||||
id: number;
|
||||
@@ -21,16 +23,38 @@
|
||||
export let onSetEditImage: (file: File | null) => void;
|
||||
export let onCancelEdit: (id: number) => void;
|
||||
|
||||
// For previewing the new image
|
||||
let previewUrl: string | null = null;
|
||||
|
||||
$: if (editImage) {
|
||||
previewUrl = URL.createObjectURL(editImage);
|
||||
} else {
|
||||
previewUrl = null;
|
||||
// Build a safe image URL:
|
||||
function imageUrl(img?: string | null) {
|
||||
if (!img) return null;
|
||||
// already absolute
|
||||
if (img.startsWith("http") || img.startsWith("//")) return img;
|
||||
// ensure no double slashes when API_BASE is set
|
||||
const base = (API_BASE || "").replace(/\/$/, "");
|
||||
if (base) return `${base}${img}`;
|
||||
return img; // relative path like "/uploads/..."
|
||||
}
|
||||
|
||||
const BACKEND_URL = "http://localhost:3000";
|
||||
// preview management (revoke previous object URL)
|
||||
let previewUrl: string | null = null;
|
||||
let _prevObjectUrl: string | null = null;
|
||||
$: {
|
||||
if (editImage) {
|
||||
const u = URL.createObjectURL(editImage);
|
||||
if (_prevObjectUrl) URL.revokeObjectURL(_prevObjectUrl);
|
||||
previewUrl = u;
|
||||
_prevObjectUrl = u;
|
||||
} else {
|
||||
if (_prevObjectUrl) {
|
||||
URL.revokeObjectURL(_prevObjectUrl);
|
||||
_prevObjectUrl = null;
|
||||
}
|
||||
previewUrl = null;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (_prevObjectUrl) URL.revokeObjectURL(_prevObjectUrl);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -56,11 +80,7 @@
|
||||
{#if previewUrl}
|
||||
<img src={previewUrl} alt="Preview" class="card-img" />
|
||||
{:else if counter.image}
|
||||
<img
|
||||
src={`${BACKEND_URL}${counter.image}`}
|
||||
alt={counter.name}
|
||||
class="card-img"
|
||||
/>
|
||||
<img src={imageUrl(counter.image)} alt={counter.name} class="card-img" />
|
||||
{:else}
|
||||
<div class="card-img placeholder"></div>
|
||||
{/if}
|
||||
@@ -89,10 +109,10 @@
|
||||
<div class="card-img-container">
|
||||
{#if counter.image}
|
||||
<img
|
||||
src={`${BACKEND_URL}${counter.image}`}
|
||||
alt={counter.name}
|
||||
class="card-img"
|
||||
/>
|
||||
src={imageUrl(counter.image)}
|
||||
alt={counter.name}
|
||||
class="card-img"
|
||||
/>
|
||||
{:else}
|
||||
<div class="card-img placeholder">No image</div>
|
||||
{/if}
|
||||
|
||||
3
frontend/src/config.ts
Normal file
3
frontend/src/config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const API_BASE = import.meta.env.VITE_API_URL ?? ''; // empty = same origin
|
||||
export const API_COUNTERS = `${API_BASE}/api/counters`;
|
||||
export const UPLOADS_BASE = `${API_BASE}/uploads`;
|
||||
@@ -1,7 +1,21 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
import { defineConfig } from 'vite';
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
})
|
||||
server: {
|
||||
port: Number(process.env.VITE_PORT) || 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
'/uploads': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user