diff --git a/db/migrations/1733580734_updated_users.go b/db/migrations/1733580734_updated_users.go new file mode 100644 index 00000000..70402734 --- /dev/null +++ b/db/migrations/1733580734_updated_users.go @@ -0,0 +1,55 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("_pb_users_auth_") + if err != nil { + return err + } + + // add + new_bio := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "pd2cq8sq", + "name": "bio", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": 10000, + "pattern": "" + } + }`), new_bio); err != nil { + return err + } + collection.Schema.AddField(new_bio) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("_pb_users_auth_") + if err != nil { + return err + } + + // remove + collection.Schema.RemoveField("pd2cq8sq") + + return dao.SaveCollection(collection) + }) +} diff --git a/db/migrations/1733580769_updated_users_anonymous.go b/db/migrations/1733580769_updated_users_anonymous.go new file mode 100644 index 00000000..1396a7d0 --- /dev/null +++ b/db/migrations/1733580769_updated_users_anonymous.go @@ -0,0 +1,179 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("xku110v5a5xbufa") + if err != nil { + return err + } + + options := map[string]any{} + if err := json.Unmarshal([]byte(`{ + "query": "SELECT id, username, avatar, bio, created FROM users" + }`), &options); err != nil { + return err + } + collection.SetOptions(options) + + // remove + collection.Schema.RemoveField("femc0ok5") + + // remove + collection.Schema.RemoveField("aglcodpn") + + // add + new_username := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "tkxbpwxe", + "name": "username", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }`), new_username); err != nil { + return err + } + collection.Schema.AddField(new_username) + + // add + new_avatar := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "xs5qvkih", + "name": "avatar", + "type": "file", + "required": false, + "presentable": false, + "unique": false, + "options": { + "mimeTypes": [ + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp" + ], + "thumbs": null, + "maxSelect": 1, + "maxSize": 5242880, + "protected": false + } + }`), new_avatar); err != nil { + return err + } + collection.Schema.AddField(new_avatar) + + // add + new_bio := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "agsa8h5z", + "name": "bio", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": 10000, + "pattern": "" + } + }`), new_bio); err != nil { + return err + } + collection.Schema.AddField(new_bio) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("xku110v5a5xbufa") + if err != nil { + return err + } + + options := map[string]any{} + if err := json.Unmarshal([]byte(`{ + "query": "SELECT id, username, avatar, created FROM users" + }`), &options); err != nil { + return err + } + collection.SetOptions(options) + + // add + del_username := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "femc0ok5", + "name": "username", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }`), del_username); err != nil { + return err + } + collection.Schema.AddField(del_username) + + // add + del_avatar := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "aglcodpn", + "name": "avatar", + "type": "file", + "required": false, + "presentable": false, + "unique": false, + "options": { + "mimeTypes": [ + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp" + ], + "thumbs": null, + "maxSelect": 1, + "maxSize": 5242880, + "protected": false + } + }`), del_avatar); err != nil { + return err + } + collection.Schema.AddField(del_avatar) + + // remove + collection.Schema.RemoveField("tkxbpwxe") + + // remove + collection.Schema.RemoveField("xs5qvkih") + + // remove + collection.Schema.RemoveField("agsa8h5z") + + return dao.SaveCollection(collection) + }) +} diff --git a/web/src/lib/components/nav_bar.svelte b/web/src/lib/components/nav_bar.svelte index 1dedfe08..3a73a8ef 100644 --- a/web/src/lib/components/nav_bar.svelte +++ b/web/src/lib/components/nav_bar.svelte @@ -83,7 +83,7 @@ logout(); window.location.href = "/"; } else if (item.value == "settings") { - goto("/settings/account"); + goto("/settings/profile"); } } diff --git a/web/src/lib/i18n/locales/de.json b/web/src/lib/i18n/locales/de.json index b116a31b..39d690dc 100644 --- a/web/src/lib/i18n/locales/de.json +++ b/web/src/lib/i18n/locales/de.json @@ -95,6 +95,7 @@ "explore-some-trails": "Erkunden Sie einige Routen", "export": "Exportieren", "export-all-trails": "Alle Routen exportieren", + "favourite-sport": "", "features": "Features", "file-format": "Dateiformat", "file-too-big": "Datei {file} ist zu groß (max. {size})", diff --git a/web/src/lib/i18n/locales/en.json b/web/src/lib/i18n/locales/en.json index 8768383a..e37516fa 100644 --- a/web/src/lib/i18n/locales/en.json +++ b/web/src/lib/i18n/locales/en.json @@ -95,6 +95,7 @@ "explore-some-trails": "Explore some trails", "export": "Export", "export-all-trails": "Export all trails", + "favourite-sport": "Favourite sport", "features": "Features", "file-format": "File format", "file-too-big": "File {file} is too big (max. {size})", diff --git a/web/src/lib/i18n/locales/fr.json b/web/src/lib/i18n/locales/fr.json index 4bd7e578..ecef6241 100644 --- a/web/src/lib/i18n/locales/fr.json +++ b/web/src/lib/i18n/locales/fr.json @@ -95,6 +95,7 @@ "explore-some-trails": "Explorer certains itinéraires", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "Fonctionnalités", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/hu.json b/web/src/lib/i18n/locales/hu.json index 27a2a9ab..2f4b0263 100644 --- a/web/src/lib/i18n/locales/hu.json +++ b/web/src/lib/i18n/locales/hu.json @@ -95,6 +95,7 @@ "explore-some-trails": "Fedezzen fel néhány ösvényt", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "Jellemzők", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/it.json b/web/src/lib/i18n/locales/it.json index 2f9ecffd..e8f50f22 100644 --- a/web/src/lib/i18n/locales/it.json +++ b/web/src/lib/i18n/locales/it.json @@ -95,6 +95,7 @@ "explore-some-trails": "Esplora alcuni percorsi", "export": "Esporta", "export-all-trails": "", + "favourite-sport": "", "features": "Caratteristiche", "file-format": "Formato del file", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/nl.json b/web/src/lib/i18n/locales/nl.json index 9621936f..8d8daa9c 100644 --- a/web/src/lib/i18n/locales/nl.json +++ b/web/src/lib/i18n/locales/nl.json @@ -95,6 +95,7 @@ "explore-some-trails": "Verken enkele wandelroutes", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "Kenmerken", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/pl.json b/web/src/lib/i18n/locales/pl.json index 690d7293..1551a80e 100644 --- a/web/src/lib/i18n/locales/pl.json +++ b/web/src/lib/i18n/locales/pl.json @@ -95,6 +95,7 @@ "explore-some-trails": "Eksploruj różne ścieżki", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "Funkcje", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/pt.json b/web/src/lib/i18n/locales/pt.json index 6b479b9d..8b4dbc79 100644 --- a/web/src/lib/i18n/locales/pt.json +++ b/web/src/lib/i18n/locales/pt.json @@ -95,6 +95,7 @@ "explore-some-trails": "Explore algumas trilhas", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "Características", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/i18n/locales/zh.json b/web/src/lib/i18n/locales/zh.json index a429316d..8ed40675 100644 --- a/web/src/lib/i18n/locales/zh.json +++ b/web/src/lib/i18n/locales/zh.json @@ -95,6 +95,7 @@ "explore-some-trails": "探索行程", "export": "", "export-all-trails": "", + "favourite-sport": "", "features": "特性", "file-format": "", "file-too-big": "", diff --git a/web/src/lib/models/user.ts b/web/src/lib/models/user.ts index 3be3c99d..f30f3066 100644 --- a/web/src/lib/models/user.ts +++ b/web/src/lib/models/user.ts @@ -6,6 +6,7 @@ export type User = { email?: string, password: string, avatar?: string; + bio?: string; language?: string; created?: string; } @@ -14,5 +15,6 @@ export type UserAnonymous = { id: string, username?: string, avatar?: string; + bio?: string; created?: string; } \ No newline at end of file diff --git a/web/src/routes/profile/[id]/+layout.server.ts b/web/src/routes/profile/[id]/+layout.server.ts new file mode 100644 index 00000000..1d174a56 --- /dev/null +++ b/web/src/routes/profile/[id]/+layout.server.ts @@ -0,0 +1,15 @@ +import { users_show } from "$lib/stores/user_store"; +import { error, type ServerLoad } from "@sveltejs/kit"; + +export const load: ServerLoad = async ({ params, locals, fetch }) => { + + if(!params.id) { + error(404, "Not found") + } + + const user = await users_show(params.id, fetch); + + const isOwnProfile = params.id === locals.user?.id; + + return { user, isOwnProfile } +}; \ No newline at end of file diff --git a/web/src/routes/profile/[id]/+layout.svelte b/web/src/routes/profile/[id]/+layout.svelte new file mode 100644 index 00000000..0fc237d2 --- /dev/null +++ b/web/src/routes/profile/[id]/+layout.svelte @@ -0,0 +1,73 @@ + + +
+
+ {#if data.user} +
+ avatar +
+

+ {data.user.username} +

+

+ Joined: + {new Date(data.user.created ?? "").toLocaleDateString( + undefined, + { + month: "2-digit", + day: "2-digit", + year: "numeric", + timeZone: "UTC", + }, + )} +

+
+
+ {/if} +
+
+

0

+

Followers

+
+
+

0

+

Following

+
+
+
+ {#each profileLinks as link, i} + {link.text} + {/each} +
+
+ +
diff --git a/web/src/routes/profile/[id]/+page.svelte b/web/src/routes/profile/[id]/+page.svelte index c5fcd869..21d3dd22 100644 --- a/web/src/routes/profile/[id]/+page.svelte +++ b/web/src/routes/profile/[id]/+page.svelte @@ -1,428 +1,33 @@ - - {$_("profile")} | wanderer - - -
- {#if data.user} -
- avatar -
-

- {data.user.username} -

-

- Joined: - {new Date(data.user.created ?? "").toLocaleDateString( - undefined, - { - month: "2-digit", - day: "2-digit", - year: "numeric", - timeZone: "UTC", - }, - )} -

-
-
- {/if} -
- updateFilterCategory(e.detail)} - label={$_("categories")} - items={categorySelectItems} - placeholder={`${$_("filter-categories")}...`} - > - - -
-
-
- handleDateClick(e.detail)} - logs={$summitLogs} - colorMap={categoryColorMap} - > -
-
- {$_( - "categories", - )} - -
-
- -
-
- {$_("activity", { - values: { n: 2 }, - })} -

{$summitLogs.length}

-
-
- {$_("distance")} -

{formatDistance(totalDistance)}

-
- -
- {$_("duration")} -

- {formatTimeHHMM(totalDuration / 60)} -

-
-
- {$_( - "elevation-gain", - )} -

- {formatElevation(totalElevationGain)} -

-
-
- {$_( - "elevation-loss", - )} -

- {formatElevation(totalElevationLoss)} -

-
-
- {$_( - "average-speed", - )} -

{formatSpeed(averageSpeed)}

-
-
-
- {$_("activity", { - values: { n: 1 }, - })} +
+

+ {$_("about")} + {data.user.username} + {#if data.isOwnProfile && data.user.bio?.length} + - -

- - - `${item.dataset.label}: ${item.formattedValue} ${barChartUnit()}`, - }, - }, - }, - scales: { - y: { - ticks: { - callback: function (value, index, ticks) { - return value + " " + barChartUnit(); - }, - }, - }, - }, - }} - > -
+ {/if} + + {#if data.user.bio?.length} +

{data.user.bio}

+ {:else if data.isOwnProfile} + + Add Bio + {/if}
- -
- {$_("all-activities")} -
- -
+
+

+ {$_("list", { values: { n: 2 } })} +

+
+
+

Timeline

diff --git a/web/src/routes/profile/[id]/stats/+page.svelte b/web/src/routes/profile/[id]/stats/+page.svelte new file mode 100644 index 00000000..aff4d33e --- /dev/null +++ b/web/src/routes/profile/[id]/stats/+page.svelte @@ -0,0 +1,400 @@ + + + + {$_("profile")} | wanderer + + +
+
+ updateFilterCategory(e.detail)} + label={$_("categories")} + items={categorySelectItems} + placeholder={`${$_("filter-categories")}...`} + > + + +
+
+
+ handleDateClick(e.detail)} + logs={$summitLogs} + colorMap={categoryColorMap} + > +
+
+ {$_( + "categories", + )} + +
+
+ +
+
+ {$_("activity", { + values: { n: 2 }, + })} +

{$summitLogs.length}

+
+
+ {$_("distance")} +

{formatDistance(totalDistance)}

+
+ +
+ {$_("duration")} +

+ {formatTimeHHMM(totalDuration / 60)} +

+
+
+ {$_( + "average-speed", + )} +

{formatSpeed(averageSpeed)}

+
+
+ {$_( + "elevation-gain", + )} +

+ {formatElevation(totalElevationGain)} +

+
+
+ {$_( + "elevation-loss", + )} +

+ {formatElevation(totalElevationLoss)} +

+
+ +
+
+ {$_("activity", { + values: { n: 1 }, + })} + +
+ + + `${item.dataset.label}: ${item.formattedValue} ${barChartUnit()}`, + }, + }, + }, + scales: { + y: { + ticks: { + callback: function (value, index, ticks) { + return value + " " + barChartUnit(); + }, + }, + }, + }, + }} + > +
+
+ +
+ {$_("all-activities")} +
+ +
+
+
diff --git a/web/src/routes/profile/[id]/+page.ts b/web/src/routes/profile/[id]/stats/+page.ts similarity index 92% rename from web/src/routes/profile/[id]/+page.ts rename to web/src/routes/profile/[id]/stats/+page.ts index 35bf32b6..4df09af1 100644 --- a/web/src/routes/profile/[id]/+page.ts +++ b/web/src/routes/profile/[id]/stats/+page.ts @@ -25,7 +25,6 @@ export const load: ServerLoad = async ({ params, locals, fetch }) => { category: [] } const logs = await summit_logs_index(params.id, filter, fetch); - const user = await users_show(params.id, fetch); - return { filter, user } + return { filter } }; \ No newline at end of file diff --git a/web/src/lib/components/profile/settings.svelte b/web/src/routes/settings/+layout.svelte similarity index 51% rename from web/src/lib/components/profile/settings.svelte rename to web/src/routes/settings/+layout.svelte index 4d933f8b..ac3630ce 100644 --- a/web/src/lib/components/profile/settings.svelte +++ b/web/src/routes/settings/+layout.svelte @@ -1,18 +1,30 @@
- {#each items as item, i} + {#each settingsLinks as item, i}