diff --git a/backend/internal/data/repo/repo_items.go b/backend/internal/data/repo/repo_items.go
index 53f21a4..72ba904 100644
--- a/backend/internal/data/repo/repo_items.go
+++ b/backend/internal/data/repo/repo_items.go
@@ -799,8 +799,11 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID)
item.HasGroupWith(group.ID(GID)),
item.Or(
item.PurchaseTimeNotNil(),
+ item.PurchaseFromLT("0002-01-01"),
item.SoldTimeNotNil(),
+ item.SoldToLT("0002-01-01"),
item.WarrantyExpiresNotNil(),
+ item.WarrantyDetailsLT("0002-01-01"),
),
)
@@ -819,15 +822,36 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID)
updateQ := e.db.Item.Update().Where(item.ID(i.ID))
if !i.PurchaseTime.IsZero() {
- updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime))
+ switch {
+ case i.PurchaseTime.Year() < 100:
+ updateQ.ClearPurchaseTime()
+ default:
+ updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime))
+ }
+ } else {
+ updateQ.ClearPurchaseTime()
}
if !i.SoldTime.IsZero() {
- updateQ.SetSoldTime(toDateOnly(i.SoldTime))
+ switch {
+ case i.SoldTime.Year() < 100:
+ updateQ.ClearSoldTime()
+ default:
+ updateQ.SetSoldTime(toDateOnly(i.SoldTime))
+ }
+ } else {
+ updateQ.ClearSoldTime()
}
if !i.WarrantyExpires.IsZero() {
- updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires))
+ switch {
+ case i.WarrantyExpires.Year() < 100:
+ updateQ.ClearWarrantyExpires()
+ default:
+ updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires))
+ }
+ } else {
+ updateQ.ClearWarrantyExpires()
}
_, err = updateQ.Save(ctx)
@@ -879,7 +903,6 @@ func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, GID uuid.UUID) (
_, err = e.db.Attachment.UpdateOne(a).
SetPrimary(true).
Save(ctx)
-
if err != nil {
return updated, err
}
diff --git a/frontend/components/Form/DatePicker.vue b/frontend/components/Form/DatePicker.vue
index 98b34f3..2a681ea 100644
--- a/frontend/components/Form/DatePicker.vue
+++ b/frontend/components/Form/DatePicker.vue
@@ -9,11 +9,15 @@
-
+
diff --git a/frontend/components/global/DateTime.vue b/frontend/components/global/DateTime.vue
index 0388a67..e5a76a9 100644
--- a/frontend/components/global/DateTime.vue
+++ b/frontend/components/global/DateTime.vue
@@ -22,6 +22,6 @@
return "";
}
- return fmtDate(props.date, props.format, props.datetimeType);
+ return fmtDate(props.date, props.format);
});
diff --git a/frontend/composables/use-formatters.ts b/frontend/composables/use-formatters.ts
index 035d27f..32a2a73 100644
--- a/frontend/composables/use-formatters.ts
+++ b/frontend/composables/use-formatters.ts
@@ -37,7 +37,7 @@ function ordinalIndicator(num: number) {
}
}
-export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human", fmtType: DateTimeType): string {
+export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
const months = [
"January",
"February",
@@ -62,11 +62,6 @@ export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human", fmt
return "";
}
- if (fmtType === "date") {
- // Offset local time
- dt.setHours(dt.getHours() + dt.getTimezoneOffset() / 60);
- }
-
switch (fmt) {
case "relative":
return useTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
diff --git a/frontend/composables/use-theme.ts b/frontend/composables/use-theme.ts
index cbd26d3..89e3d39 100644
--- a/frontend/composables/use-theme.ts
+++ b/frontend/composables/use-theme.ts
@@ -38,3 +38,27 @@ export function useTheme(): UseTheme {
return { theme, setTheme };
}
+
+export function useIsDark() {
+ const theme = useTheme();
+
+ const darkthemes = [
+ "synthwave",
+ "retro",
+ "cyberpunk",
+ "valentine",
+ "halloween",
+ "forest",
+ "aqua",
+ "black",
+ "luxury",
+ "dracula",
+ "business",
+ "night",
+ "coffee",
+ ];
+
+ return computed(() => {
+ return darkthemes.includes(theme.theme.value);
+ });
+}
diff --git a/frontend/lib/datelib/datelib.test.ts b/frontend/lib/datelib/datelib.test.ts
new file mode 100644
index 0000000..171d2cc
--- /dev/null
+++ b/frontend/lib/datelib/datelib.test.ts
@@ -0,0 +1,43 @@
+import { describe, test, expect } from "vitest";
+import { format, zeroTime, factorRange, parse } from "./datelib";
+
+describe("format", () => {
+ test("should format a date as a string", () => {
+ const date = new Date(2020, 1, 1);
+ expect(format(date)).toBe("2020-02-01");
+ });
+
+ test("should return the string if a string is passed in", () => {
+ expect(format("2020-02-01")).toBe("2020-02-01");
+ });
+});
+
+describe("zeroTime", () => {
+ test("should zero out the time", () => {
+ const date = new Date(2020, 1, 1, 12, 30, 30);
+ const zeroed = zeroTime(date);
+ expect(zeroed.getHours()).toBe(0);
+ expect(zeroed.getMinutes()).toBe(0);
+ expect(zeroed.getSeconds()).toBe(0);
+ });
+});
+
+describe("factorRange", () => {
+ test("should return a range of dates", () => {
+ const [start, end] = factorRange(10);
+ // Start should be today
+ expect(start).toBeInstanceOf(Date);
+ expect(start.getFullYear()).toBe(new Date().getFullYear());
+
+ // End should be 10 days from now
+ expect(end).toBeInstanceOf(Date);
+ expect(end.getFullYear()).toBe(new Date().getFullYear());
+ });
+});
+
+describe("parse", () => {
+ test("should parse a date string", () => {
+ const date = parse("2020-02-01");
+ expect(date).toBeInstanceOf(Date);
+ });
+});
diff --git a/frontend/lib/datelib/datelib.ts b/frontend/lib/datelib/datelib.ts
new file mode 100644
index 0000000..c70dbf9
--- /dev/null
+++ b/frontend/lib/datelib/datelib.ts
@@ -0,0 +1,34 @@
+import { addDays } from "date-fns";
+
+/*
+ * Formats a date as a string
+ * */
+export function format(date: Date | string): string {
+ if (typeof date === "string") {
+ return date;
+ }
+ return date.toISOString().split("T")[0];
+}
+
+export function zeroTime(date: Date): Date {
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
+}
+
+export function factorRange(offset: number = 7): [Date, Date] {
+ const date = zeroTime(new Date());
+
+ return [date, addDays(date, offset)];
+}
+
+export function factory(offset = 0): Date {
+ if (offset) {
+ return addDays(zeroTime(new Date()), offset);
+ }
+
+ return zeroTime(new Date());
+}
+
+export function parse(yyyyMMdd: string): Date {
+ const parts = yyyyMMdd.split("-");
+ return new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
+}
diff --git a/frontend/package.json b/frontend/package.json
index e63b826..8eb8a95 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -41,10 +41,12 @@
"@tailwindcss/aspect-ratio": "^0.4.0",
"@tailwindcss/forms": "^0.5.2",
"@tailwindcss/typography": "^0.5.4",
+ "@vuepic/vue-datepicker": "^8.1.1",
"@vueuse/nuxt": "^10.0.0",
"@vueuse/router": "^10.0.0",
"autoprefixer": "^10.4.8",
"daisyui": "^2.24.0",
+ "date-fns": "^3.3.1",
"dompurify": "^3.0.0",
"h3": "^1.7.1",
"http-proxy": "^1.18.1",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index dc10375..1958dc6 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -26,6 +26,9 @@ dependencies:
'@tailwindcss/typography':
specifier: ^0.5.4
version: 0.5.8(tailwindcss@3.2.4)
+ '@vuepic/vue-datepicker':
+ specifier: ^8.1.1
+ version: 8.1.1(vue@3.3.4)
'@vueuse/nuxt':
specifier: ^10.0.0
version: 10.0.0(nuxt@3.6.5)(rollup@2.79.1)(vue@3.3.4)
@@ -38,6 +41,9 @@ dependencies:
daisyui:
specifier: ^2.24.0
version: 2.43.0(autoprefixer@10.4.13)(postcss@8.4.19)
+ date-fns:
+ specifier: ^3.3.1
+ version: 3.3.1
dompurify:
specifier: ^3.0.0
version: 3.0.0
@@ -114,7 +120,7 @@ devDependencies:
version: 5.0.2
vite-plugin-eslint:
specifier: ^1.8.1
- version: 1.8.1(eslint@8.29.0)(vite@4.3.9)
+ version: 1.8.1(eslint@8.29.0)(vite@5.0.5)
vitest:
specifier: ^1.0.0
version: 1.0.0(@types/node@18.11.12)
@@ -3160,7 +3166,7 @@ packages:
'@nuxt/kit': 3.6.5(rollup@2.79.1)
pathe: 1.1.1
ufo: 1.3.2
- vite-plugin-pwa: 0.16.7(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0)
+ vite-plugin-pwa: 0.16.7(vite@5.0.5)(workbox-build@7.0.0)(workbox-window@7.0.0)
dev: true
/@vitejs/plugin-vue-jsx@3.0.1(vite@4.3.9)(vue@3.3.4):
@@ -3343,6 +3349,16 @@ packages:
/@vue/shared@3.3.4:
resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==}
+ /@vuepic/vue-datepicker@8.1.1(vue@3.3.4):
+ resolution: {integrity: sha512-/t9+dROb/hYN/DInff8ctIiVm5tVyuJdiWA+nWcjHOLjUhvAQ9vyJwhxAkoWX5o0EB5x5XeCME2cajfTPz86RA==}
+ engines: {node: '>=18.12.0'}
+ peerDependencies:
+ vue: '>=3.2.0'
+ dependencies:
+ date-fns: 3.3.1
+ vue: 3.3.4
+ dev: false
+
/@vueuse/core@10.0.0(vue@3.3.4):
resolution: {integrity: sha512-Q/p2xaGVFVrJ0E4ID1SM35WIa0Eo4AeKPSLKuLpYG09zgUWuwEaY4lBoNzLzkdLjzq5goIJ3DfYFI0wt8W4MkA==}
dependencies:
@@ -4066,7 +4082,7 @@ packages:
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@@ -4456,6 +4472,10 @@ packages:
resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==}
engines: {node: '>= 12'}
+ /date-fns@3.3.1:
+ resolution: {integrity: sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==}
+ dev: false
+
/debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
@@ -5532,19 +5552,11 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- /fsevents@2.3.2:
- resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
- requiresBuild: true
- optional: true
-
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/function-bind@1.1.1:
@@ -7021,7 +7033,7 @@ packages:
engines: {node: ^14.18.0 || >=16.10.0}
hasBin: true
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
/nuxt@3.6.5(@types/node@18.11.12)(eslint@8.29.0)(rollup@2.79.1)(typescript@5.0.2):
resolution: {integrity: sha512-0A7V8B1HrIXX9IlqPc2w+5ZPXi+7MYa9QVhtuGYuLvjRKoSFANhCoMPRP6pKdoxigM1MBxhLue2VmHA/VbtJCw==}
@@ -8223,14 +8235,14 @@ packages:
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
/rollup@3.26.2:
resolution: {integrity: sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
/rollup@4.6.1:
resolution: {integrity: sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==}
@@ -9361,7 +9373,7 @@ packages:
vscode-languageserver-textdocument: 1.0.8
vscode-uri: 3.0.6
- /vite-plugin-eslint@1.8.1(eslint@8.29.0)(vite@4.3.9):
+ /vite-plugin-eslint@1.8.1(eslint@8.29.0)(vite@5.0.5):
resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
peerDependencies:
eslint: '>=7'
@@ -9371,10 +9383,10 @@ packages:
'@types/eslint': 8.4.10
eslint: 8.29.0
rollup: 2.79.1
- vite: 4.3.9(@types/node@18.11.12)
+ vite: 5.0.5(@types/node@18.11.12)
dev: true
- /vite-plugin-pwa@0.16.7(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0):
+ /vite-plugin-pwa@0.16.7(vite@5.0.5)(workbox-build@7.0.0)(workbox-window@7.0.0):
resolution: {integrity: sha512-4WMA5unuKlHs+koNoykeuCfTcqEGbiTRr8sVYUQMhc6tWxZpSRnv9Ojk4LKmqVhoPGHfBVCdGaMo8t9Qidkc1Q==}
engines: {node: '>=16.0.0'}
peerDependencies:
@@ -9385,7 +9397,7 @@ packages:
debug: 4.3.4
fast-glob: 3.3.2
pretty-bytes: 6.1.1
- vite: 4.3.9(@types/node@18.11.12)
+ vite: 5.0.5(@types/node@18.11.12)
workbox-build: 7.0.0
workbox-window: 7.0.0
transitivePeerDependencies:
@@ -9422,7 +9434,7 @@ packages:
postcss: 8.4.24
rollup: 3.26.2
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
/vite@5.0.5(@types/node@18.11.12):
resolution: {integrity: sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==}