forked from jmug/cactoide
fix: refactor, docker, dateformatter
This commit is contained in:
43
Dockerfile
43
Dockerfile
@@ -1,47 +1,24 @@
|
|||||||
# Use Node.js 20 Alpine for smaller image size
|
FROM node:20-alpine AS builder
|
||||||
FROM node:20-alpine AS base
|
|
||||||
|
|
||||||
# Install dependencies only when needed
|
|
||||||
FROM base AS deps
|
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
|
||||||
RUN apk add --no-cache libc6-compat
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY package*.json .
|
||||||
|
|
||||||
# Install dependencies based on the preferred package manager
|
|
||||||
COPY package.json package-lock.json* ./
|
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
# Rebuild the source code only when needed
|
|
||||||
FROM base AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the application
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
RUN npm prune --production
|
||||||
|
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
# Production image, copy all the files and run the app
|
|
||||||
FROM base AS runner
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV production
|
COPY --from=builder /app/build build/
|
||||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
COPY --from=builder /app/node_modules node_modules/
|
||||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
COPY package.json .
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
|
||||||
RUN adduser --system --uid 1001 sveltekit
|
|
||||||
|
|
||||||
# Copy the built application
|
|
||||||
COPY --from=builder --chown=sveltekit:nodejs /app/build ./build
|
|
||||||
COPY --from=builder --chown=sveltekit:nodejs /app/package.json ./package.json
|
|
||||||
COPY --from=builder --chown=sveltekit:nodejs /app/node_modules ./node_modules
|
|
||||||
|
|
||||||
USER sveltekit
|
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENV PORT 3000
|
ENV PORT 3000
|
||||||
ENV HOSTNAME "0.0.0.0"
|
ENV HOSTNAME "0.0.0.0"
|
||||||
|
ENV NODE_ENV production
|
||||||
# Start the application
|
CMD [ "node", "build" ]
|
||||||
CMD ["node", "build"]
|
|
||||||
|
|||||||
328
package-lock.json
generated
328
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@
|
|||||||
"@eslint/compat": "^1.2.5",
|
"@eslint/compat": "^1.2.5",
|
||||||
"@eslint/js": "^9.18.0",
|
"@eslint/js": "^9.18.0",
|
||||||
"@sveltejs/adapter-auto": "^6.0.0",
|
"@sveltejs/adapter-auto": "^6.0.0",
|
||||||
"@sveltejs/adapter-netlify": "^5.2.2",
|
|
||||||
"@sveltejs/kit": "^2.22.0",
|
"@sveltejs/kit": "^2.22.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
@@ -39,6 +38,7 @@
|
|||||||
"vite": "^7.0.4"
|
"vite": "^7.0.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sveltejs/adapter-node": "^5.3.1",
|
||||||
"drizzle-orm": "^0.44.5",
|
"drizzle-orm": "^0.44.5",
|
||||||
"postgres": "^3.4.7"
|
"postgres": "^3.4.7"
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/lib/dateFormatter.ts
Normal file
12
src/lib/dateFormatter.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export const formatDate = (dateString: string): string => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
return `${year}/${month}/${day}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formatTime = (timeString: string): string => {
|
||||||
|
const [hours, minutes] = timeString.split(':');
|
||||||
|
return `${hours}:${minutes}`;
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export type EventType = 'limited' | 'unlimited';
|
export type EventType = 'limited' | 'unlimited';
|
||||||
export type EventVisibility = 'public' | 'private';
|
export type EventVisibility = 'public' | 'private';
|
||||||
|
export type ActionType = 'add' | 'remove';
|
||||||
|
|
||||||
export interface Event {
|
export interface Event {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { Event } from '$lib/types';
|
import type { Event } from '$lib/types';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import type { PageData } from '../$types';
|
import type { PageData } from '../$types';
|
||||||
|
import { formatTime, formatDate } from '$lib/dateFormatter';
|
||||||
|
|
||||||
let publicEvents: Event[] = [];
|
let publicEvents: Event[] = [];
|
||||||
let error = '';
|
let error = '';
|
||||||
@@ -9,19 +10,6 @@
|
|||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
// Use the server-side data
|
// Use the server-side data
|
||||||
$: publicEvents = data.events;
|
$: publicEvents = data.events;
|
||||||
|
|
||||||
function formatDate(dateString: string): string {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
|
||||||
return `${year}/${month}/${day}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(timeString: string): string {
|
|
||||||
const [hours, minutes] = timeString.split(':');
|
|
||||||
return `${hours}:${minutes}`;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Event } from '$lib/types';
|
import type { Event } from '$lib/types';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { formatTime, formatDate } from '$lib/dateFormatter';
|
||||||
|
|
||||||
export let data: { events: Event[] };
|
export let data: { events: Event[] };
|
||||||
|
|
||||||
@@ -56,19 +57,6 @@
|
|||||||
showDeleteModal = false;
|
showDeleteModal = false;
|
||||||
eventToDelete = null;
|
eventToDelete = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDate(dateString: string): string {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
|
||||||
return `${year}/${month}/${day}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(timeString: string): string {
|
|
||||||
const [hours, minutes] = timeString.split(':');
|
|
||||||
return `${hours}:${minutes}`;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|||||||
@@ -117,15 +117,14 @@ export const actions: Actions = {
|
|||||||
createdAt: new Date()
|
createdAt: new Date()
|
||||||
});
|
});
|
||||||
|
|
||||||
return { success: true };
|
return { success: true, type: 'add' };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error adding RSVP:', err);
|
console.error('Error adding RSVP:', err);
|
||||||
return fail(500, { error: 'Failed to add RSVP' });
|
return fail(500, { error: 'Failed to add RSVP' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeRSVP: async ({ request, params }) => {
|
removeRSVP: async ({ request }) => {
|
||||||
const eventId = params.id;
|
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
|
|
||||||
const rsvpId = formData.get('rsvpId') as string;
|
const rsvpId = formData.get('rsvpId') as string;
|
||||||
@@ -136,7 +135,7 @@ export const actions: Actions = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await drizzleQuery.delete(rsvps).where(eq(rsvps.id, rsvpId));
|
await drizzleQuery.delete(rsvps).where(eq(rsvps.id, rsvpId));
|
||||||
return { success: true };
|
return { success: true, type: 'remove' };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error removing RSVP:', err);
|
console.error('Error removing RSVP:', err);
|
||||||
return fail(500, { error: 'Failed to remove RSVP' });
|
return fail(500, { error: 'Failed to remove RSVP' });
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import type { Event, RSVP } from '$lib/types';
|
import type { Event, RSVP } from '$lib/types';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
|
import { formatTime, formatDate } from '$lib/dateFormatter';
|
||||||
|
|
||||||
export let data: { event: Event; rsvps: RSVP[]; userId: string };
|
export let data: { event: Event; rsvps: RSVP[]; userId: string };
|
||||||
export let form;
|
export let form;
|
||||||
@@ -34,19 +35,6 @@
|
|||||||
|
|
||||||
const eventId = $page.params.id;
|
const eventId = $page.params.id;
|
||||||
|
|
||||||
function formatDate(dateString: string, timeString: string): string {
|
|
||||||
const date = new Date(`${dateString}T${timeString}`);
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
|
||||||
return `${year}/${month}/${day}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(timeString: string): string {
|
|
||||||
const [hours, minutes] = timeString.split(':');
|
|
||||||
return `${hours}:${minutes}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyEventLink() {
|
function copyEventLink() {
|
||||||
const url = `${window.location.origin}/event/${eventId}`;
|
const url = `${window.location.origin}/event/${eventId}`;
|
||||||
navigator.clipboard.writeText(url).then(() => {
|
navigator.clipboard.writeText(url).then(() => {
|
||||||
@@ -329,11 +317,19 @@
|
|||||||
|
|
||||||
<!-- Success/Error Messages -->
|
<!-- Success/Error Messages -->
|
||||||
{#if success}
|
{#if success}
|
||||||
<div
|
{#if form?.type === 'add'}
|
||||||
class="fixed right-4 bottom-4 z-40 w-128 rounded-sm border border-green-500/30 bg-green-900/20 p-4 text-green-400"
|
<div
|
||||||
>
|
class="fixed right-4 bottom-4 z-40 w-128 rounded-sm border border-green-500/30 bg-green-900/20 p-4 text-green-400"
|
||||||
{success}
|
>
|
||||||
</div>
|
{success}
|
||||||
|
</div>
|
||||||
|
{:else if form?.type === 'remove'}
|
||||||
|
<div
|
||||||
|
class="fixed right-4 bottom-4 z-40 w-128 rounded-sm border border-yellow-500/30 bg-yellow-900/20 p-4 text-yellow-400"
|
||||||
|
>
|
||||||
|
Removed RSVP successfully.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if error}
|
{#if error}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import adapter from '@sveltejs/adapter-netlify';
|
import adapter from '@sveltejs/adapter-node';
|
||||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
@@ -15,7 +15,10 @@ const config = {
|
|||||||
// see "split" mode in https://github.com/sveltejs/kit/tree/main/packages/adapter-netlify
|
// see "split" mode in https://github.com/sveltejs/kit/tree/main/packages/adapter-netlify
|
||||||
edge: false,
|
edge: false,
|
||||||
split: false
|
split: false
|
||||||
})
|
}),
|
||||||
|
csrf: {
|
||||||
|
checkOrigin: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,4 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "bundler"
|
"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
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user