(add): Main branch, (change): property to method conversion

This commit is contained in:
dbob16 committed 2026-08-05 15:44:23 -04:00
1 parent 86a81e339c
commit 4869c119d0
7 files changed
+154 -116

No files matched your search

+13 -30
View File
@@ -1,42 +1,25 @@
# sv
# Ticket Auction Manager (Client)
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
The contents of this directory of the Ticket Auction Manager repo pertains to just the client side. Which is a web-based client interface, allowing users to use Ticket Auction Manager.
## Creating a project
Due to dev resources already being in the main repo, I have decided to make this dedicated to users instead of developers.
If you're seeing this, you've probably already done this step. Congrats!
## Running TAM
```sh
# create a new project
npx sv create my-app
```
You have some choice when it comes to running TAM, using Docker or through a portable Node environment (coming soon!).
To recreate this project with the same configuration:
### Docker
```sh
# recreate this project
pnpm dlx sv@0.16.1 create --template minimal --no-types --add prettier eslint tailwindcss="plugins:none" sveltekit-adapter="adapter:node" drizzle="database:sqlite+sqlite:better-sqlite3" --install pnpm ./client
```
Docker images are available under the dbob16/tam-client repo within Docker Hub. To pull the latest image:
## Developing
`docker pull dbob16/tam-client:latest`
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
Then to run it:
```sh
npm run dev
`docker run -d --name tam-client --network host --restart unless-stopped -e host=127.0.0.1 -e port=3000 -v tam-data:/data dbob16/tam-client:latest`
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
It should then be available in a web browser at `http://localhost:3000` on the computer it is being run on. You can bookmark or make shortcuts to it for user convenience.
## Building
#### Port Conflict
To create a production version of your app:
```sh
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
If there is a conflict with the port when you go to start TAM, you can change the port by changing the number in the `-e port=3000` to another integer. For instance, if you have to change it to port 3001, you can change it to `-e port=3001` and then navigate to `http://localhost:3001` instead.
@@ -40,7 +40,7 @@
onclick={(e) => {
e.target.select();
}}
onchange={() => {
oninput={() => {
if (functions.pagerFromUpdate) functions.pagerFromUpdate();
}}
bind:value={pager.idFrom}
+19 -23
View File
@@ -27,11 +27,11 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsLength = $derived(items.length || 1);
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
functions.save();
async getPage(){
this.save();
if (pager.idFrom > pager.idTo) {
[pager.idFrom, pager.idTo] = [pager.idTo, pager.idFrom];
}
@@ -45,13 +45,9 @@
setTimeout(() => focusIdx(0));
},
pagerFromUpdate(){
if (itemsLength === 0) {
pager.idTo = pager.idFrom;
} else {
pager.idTo = pager.idFrom + (itemsLength - 1);
}
pager.idTo = pager.idFrom + (itemsLength - 1);
},
save: async () => {
async save(){
if (itemsBuffer.length > 0) {
const res = await fetch('/api/baskets', {
method: 'POST',
@@ -68,15 +64,15 @@
focusIdx(0);
}, 1);
},
prevPage: () => {
prevPage(){
((pager.idFrom -= itemsLength), (pager.idTo -= itemsLength));
functions.getPage();
this.getPage();
},
nextPage: () => {
nextPage(){
((pager.idFrom += itemsLength), (pager.idTo += itemsLength));
functions.getPage();
this.getPage();
},
nextLine: () => {
nextLine(){
if (items[nextIdx]) {
setTimeout(() => {
focusIdx(nextIdx);
@@ -87,7 +83,7 @@
}, 1);
}
},
prevLine: () => {
prevLine(){
if (curIdx > 0) {
setTimeout(() => {
focusIdx(prevIdx);
@@ -98,27 +94,27 @@
}, 1);
}
},
dupDown: () => {
dupDown(){
if (items[nextIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 'b_id'].forEach((key) => delete buffer[key]);
items[nextIdx] = { ...items[nextIdx], ...buffer, changed: true };
functions.nextLine();
this.nextLine();
} else {
focusIdx(curIdx);
}
},
dupUp: () => {
dupUp(){
if (curIdx > 0) {
const buffer = { ...items[curIdx] };
['prefix', 'b_id'].forEach((key) => delete buffer[key]);
items[prevIdx] = { ...items[prevIdx], ...buffer, changed: true };
functions.prevLine();
this.prevLine();
} else {
focusIdx(curIdx);
}
},
copy: () => {
copy(){
if (items[curIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
@@ -126,7 +122,7 @@
}
focusIdx(curIdx);
},
paste: () => {
paste(){
if (items[curIdx]) {
const buffer = JSON.parse(window.localStorage.getItem('tam-basket'));
items[curIdx] = { ...items[curIdx], ...buffer, changed: true };
@@ -186,7 +182,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_first"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.description}
/></td
>
@@ -195,7 +191,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_second"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.donors}
/></td
>
+20 -24
View File
@@ -27,11 +27,11 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsLength = $derived(items.length || 1);
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
functions.save();
async getPage(){
this.save();
if (pager.idFrom > pager.idTo) {
[pager.idFrom, pager.idTo] = [pager.idTo, pager.idFrom];
}
@@ -44,14 +44,7 @@
items = [...resData];
setTimeout(() => focusIdx(0));
},
pagerFromUpdate(){
if (itemsLength === 0) {
pager.idTo = pager.idFrom;
} else {
pager.idTo = pager.idFrom + (itemsLength - 1);
}
},
save: async () => {
async save(){
if (itemsBuffer.length > 0) {
const res = await fetch('/api/drawing', {
method: 'POST',
@@ -68,15 +61,18 @@
focusIdx(0);
}, 1);
},
prevPage: () => {
pagerFromUpdate(){
pager.idTo = pager.idFrom + (itemsLength - 1);
},
prevPage(){
((pager.idFrom -= itemsLength), (pager.idTo -= itemsLength));
functions.getPage();
this.getPage();
},
nextPage: () => {
nextPage(){
((pager.idFrom += itemsLength), (pager.idTo += itemsLength));
functions.getPage();
this.getPage();
},
nextLine: () => {
nextLine(){
if (items[nextIdx]) {
setTimeout(() => {
focusIdx(nextIdx);
@@ -87,7 +83,7 @@
}, 1);
}
},
prevLine: () => {
prevLine(){
if (curIdx > 0) {
setTimeout(() => {
focusIdx(prevIdx);
@@ -98,27 +94,27 @@
}, 1);
}
},
dupDown: () => {
dupDown(){
if (items[nextIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 'b_id'].forEach((key) => delete buffer[key]);
items[nextIdx] = { ...items[nextIdx], ...buffer, changed: true };
functions.nextLine();
this.nextLine();
} else {
focusIdx(curIdx);
}
},
dupUp: () => {
dupUp(){
if (curIdx > 0) {
const buffer = { ...items[curIdx] };
['prefix', 'b_id'].forEach((key) => delete buffer[key]);
items[prevIdx] = { ...items[prevIdx], ...buffer, changed: true };
functions.prevLine();
this.prevLine();
} else {
focusIdx(curIdx);
}
},
copy: () => {
copy(){
if (items[curIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 'b_id'].forEach((key) => delete buffer[key]);
@@ -126,7 +122,7 @@
}
focusIdx(curIdx);
},
paste: () => {
paste(){
if (items[curIdx]) {
const buffer = JSON.parse(window.localStorage.getItem('tam-drawing'));
items[curIdx] = { ...items[curIdx], ...buffer, changed: true };
@@ -187,7 +183,7 @@
type="number"
class="{iS.normal} w-full"
id="{idx}_first"
onchangecapture={async () => {
oninput={async () => {
item.changed = true;
const res = await fetch(`/api/tickets/${prefix.prefix}/${item.winning_ticket}`);
if (res.ok) {
+13 -13
View File
@@ -34,7 +34,7 @@
let items = $state([]);
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
search: async () => {
async search(){
const searchParams = new URLSearchParams({ ...searchForm });
const res = await fetch(`/api/search/tickets?${searchParams.toString()}`);
if (res.ok) {
@@ -43,7 +43,7 @@
setTimeout(() => focusIdx(0), 1);
}
},
save: async () => {
async save(){
if (itemsBuffer.length > 0) {
const res = await fetch('/api/search/tickets', {
method: 'POST',
@@ -60,7 +60,7 @@
focusIdx(0);
}, 1);
},
nextLine: () => {
nextLine(){
if (items[nextIdx]) {
setTimeout(() => {
focusIdx(nextIdx);
@@ -71,7 +71,7 @@
}, 1);
}
},
prevLine: () => {
prevLine(){
if (curIdx > 0) {
setTimeout(() => {
focusIdx(prevIdx);
@@ -82,27 +82,27 @@
}, 1);
}
},
dupDown: () => {
dupDown(){
if (items[nextIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
items[nextIdx] = { ...items[nextIdx], ...buffer, changed: true };
functions.nextLine();
this.nextLine();
} else {
focusIdx(curIdx);
}
},
dupUp: () => {
dupUp(){
if (curIdx > 0) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
items[prevIdx] = { ...items[prevIdx], ...buffer, changed: true };
functions.prevLine();
this.prevLine();
} else {
focusIdx(curIdx);
}
},
copy: () => {
copy(){
if (items[curIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
@@ -110,7 +110,7 @@
}
setTimeout(() => focusIdx(curIdx), 1);
},
paste: () => {
paste(){
if (items[curIdx]) {
const buffer = JSON.parse(window.localStorage.getItem('tam-ticket'));
items[curIdx] = { ...items[curIdx], ...buffer, changed: true };
@@ -171,7 +171,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_first"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.first_name}
/></td
>
@@ -180,7 +180,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_second"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.last_name}
/></td
>
@@ -189,7 +189,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_third"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.phone_number}
/></td
>
+19 -23
View File
@@ -27,11 +27,11 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsLength = $derived(items.length || 1);
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
functions.save();
async getPage(){
this.save();
if (pager.idFrom > pager.idTo) {
[pager.idFrom, pager.idTo] = [pager.idTo, pager.idFrom];
}
@@ -45,13 +45,9 @@
setTimeout(() => focusIdx(0));
},
pagerFromUpdate(){
if (itemsLength === 0) {
pager.idTo = pager.idFrom;
} else {
pager.idTo = pager.idFrom + (itemsLength - 1);
}
pager.idTo = pager.idFrom + (itemsLength - 1);
},
save: async () => {
async save(){
if (itemsBuffer.length > 0) {
const res = await fetch('/api/tickets', {
method: 'POST',
@@ -68,15 +64,15 @@
focusIdx(0);
}, 1);
},
prevPage: () => {
prevPage(){
((pager.idFrom -= itemsLength), (pager.idTo -= itemsLength));
functions.getPage();
this.getPage();
},
nextPage: () => {
nextPage(){
((pager.idFrom += itemsLength), (pager.idTo += itemsLength));
functions.getPage();
this.getPage();
},
nextLine: () => {
nextLine(){
if (items[nextIdx]) {
setTimeout(() => {
focusIdx(nextIdx);
@@ -87,7 +83,7 @@
}, 1);
}
},
prevLine: () => {
prevLine(){
if (curIdx > 0) {
setTimeout(() => {
focusIdx(prevIdx);
@@ -98,17 +94,17 @@
}, 1);
}
},
dupDown: () => {
dupDown(){
if (items[nextIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
items[nextIdx] = { ...items[nextIdx], ...buffer, changed: true };
functions.nextLine();
this.nextLine();
} else {
focusIdx(curIdx);
}
},
dupUp: () => {
dupUp(){
if (curIdx > 0) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
@@ -118,7 +114,7 @@
focusIdx(curIdx);
}
},
copy: () => {
copy(){
if (items[curIdx]) {
const buffer = { ...items[curIdx] };
['prefix', 't_id'].forEach((key) => delete buffer[key]);
@@ -126,7 +122,7 @@
}
setTimeout(() => focusIdx(curIdx), 1);
},
paste: () => {
paste(){
if (items[curIdx]) {
const buffer = JSON.parse(window.localStorage.getItem('tam-ticket'));
items[curIdx] = { ...items[curIdx], ...buffer, changed: true };
@@ -186,7 +182,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_first"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.first_name}
/></td
>
@@ -195,7 +191,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_second"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.last_name}
/></td
>
@@ -204,7 +200,7 @@
type="text"
class="{iS.normal} w-full"
id="{idx}_third"
onchangecapture={() => (item.changed = true)}
oninput={() => (item.changed = true)}
bind:value={item.phone_number}
/></td
>