diff --git a/auth/dbc/users.sql.go b/auth/dbc/users.sql.go index 3d8bfbb4..1426d231 100644 --- a/auth/dbc/users.sql.go +++ b/auth/dbc/users.sql.go @@ -276,7 +276,7 @@ set username = coalesce($2, username), email = coalesce($3, email), password = coalesce($4, password), - claims = coalesce($5, claims) + claims = claims || coalesce($5, '{}'::jsonb) where id = $1 returning diff --git a/auth/shell.nix b/auth/shell.nix index cea77c33..0cf2b1f4 100644 --- a/auth/shell.nix +++ b/auth/shell.nix @@ -10,6 +10,6 @@ pkgs.mkShell { postgresql_15 pgformatter # to run tests - # hurl + hurl ]; } diff --git a/auth/sql/queries/users.sql b/auth/sql/queries/users.sql index f73dce75..bc888803 100644 --- a/auth/sql/queries/users.sql +++ b/auth/sql/queries/users.sql @@ -72,7 +72,7 @@ set username = coalesce(sqlc.narg(username), username), email = coalesce(sqlc.narg(email), email), password = coalesce(sqlc.narg(password), password), - claims = coalesce(sqlc.narg(claims), claims) + claims = claims || coalesce(sqlc.narg(claims), '{}'::jsonb) where id = $1 returning diff --git a/auth/tests/change-password.hurl b/auth/tests/change-password.hurl index 5ff69a04..9806c3b0 100644 --- a/auth/tests/change-password.hurl +++ b/auth/tests/change-password.hurl @@ -26,7 +26,16 @@ jwt: jsonpath "$.token" PATCH {{host}}/users/me/password Authorization: Bearer {{jwt}} { - "password": "new-password" + "oldPassword": "invalid-one", + "newPassword": "wont-be-changed" +} +HTTP 403 + +PATCH {{host}}/users/me/password +Authorization: Bearer {{jwt}} +{ + "oldPassword": "password-login-user", + "newPassword": "new-password" } HTTP 204 diff --git a/auth/users.go b/auth/users.go index 24406478..81a75c5d 100644 --- a/auth/users.go +++ b/auth/users.go @@ -59,7 +59,8 @@ type EditUserDto struct { } type EditPasswordDto struct { - Password string `json:"password" validate:"required" example:"password1234"` + OldPassword string `json:"oldPassword" validate:"required" example:"password1234"` + NewPassword string `json:"newPassword" validate:"required" example:"password1234"` } func MapDbUser(user *dbc.User) User { @@ -182,7 +183,7 @@ func (h *Handler) GetMe(c echo.Context) error { if err != nil { return err } - dbuser, err := h.db.GetUser(context.Background(), dbc.GetUserParams{ + dbuser, err := h.db.GetUser(c.Request().Context(), dbc.GetUserParams{ UseId: true, Id: id, }) @@ -406,6 +407,10 @@ func (h *Handler) ChangePassword(c echo.Context) error { if err != nil { return err } + user, err := h.db.GetUser(c.Request().Context(), dbc.GetUserParams{ + UseId: true, + Id: uid, + }) sid, err := GetCurrentSessionId(c) if err != nil { @@ -421,13 +426,26 @@ func (h *Handler) ChangePassword(c echo.Context) error { return err } + match, err := argon2id.ComparePasswordAndHash( + req.OldPassword, + *user[0].User.Password, + ) + if err != nil { + return err + } + if !match { + return echo.NewHTTPError(http.StatusForbidden, "Invalid password") + } + + pass, err := argon2id.CreateHash(req.NewPassword, argon2id.DefaultParams) + if err != nil { + return err + } _, err = h.db.UpdateUser(context.Background(), dbc.UpdateUserParams{ Id: uid, - Password: &req.Password, + Password: &pass, }) - if err == pgx.ErrNoRows { - return echo.NewHTTPError(http.StatusNotFound, "Invalid token, user not found") - } else if err != nil { + if err != nil { return err } diff --git a/front/Dockerfile b/front/Dockerfile index 5db071c6..e0d53f86 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -1,12 +1,14 @@ FROM oven/bun AS builder WORKDIR /app -# idk why it doesnt' build without it +# https://github.com/oven-sh/bun/issues/24538 +# Remember to also remove `tsx` after this bug is fixed RUN apt update && apt install -y nodejs && rm /usr/local/bun-node-fallback-bin/node ENV NODE_ENV=production -COPY package.json bun.lock scripts . +COPY package.json bun.lock . COPY scripts scripts +COPY public public RUN bun install --production COPY . . diff --git a/front/Dockerfile.dev b/front/Dockerfile.dev index 2bfbec5a..b32d1539 100644 --- a/front/Dockerfile.dev +++ b/front/Dockerfile.dev @@ -3,6 +3,7 @@ WORKDIR /app COPY package.json bun.lock . COPY scripts scripts +COPY public public RUN bun install --frozen-lockfile COPY . . diff --git a/front/app.config.ts b/front/app.config.ts index c962f03f..d898d6a0 100644 --- a/front/app.config.ts +++ b/front/app.config.ts @@ -1,4 +1,6 @@ +import "tsx/cjs"; import type { ExpoConfig } from "expo/config"; +import { supportedLanguages } from "./src/providers/translations.compile.ts"; const IS_DEV = process.env.APP_VARIANT === "development"; @@ -75,6 +77,12 @@ export const expo: ExpoConfig = { }, }, ], + [ + "react-native-localization-settings", + { + languages: supportedLanguages, + } + ] ], experiments: { typedRoutes: true, diff --git a/front/biome.json b/front/biome.json index 8c2c8f47..ca911e9e 100644 --- a/front/biome.json +++ b/front/biome.json @@ -1,6 +1,9 @@ { "extends": "//", "files": { - "includes": ["src/**"] + "includes": [ + "src/**", + "scripts/**" + ] } } diff --git a/front/bun.lock b/front/bun.lock index c2964e20..4f50bdb6 100644 --- a/front/bun.lock +++ b/front/bun.lock @@ -28,6 +28,7 @@ "expo-splash-screen": "^31.0.10", "expo-status-bar": "~3.0.8", "expo-updates": "~29.0.11", + "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", "jassub": "^1.8.6", "langmap": "^0.0.16", @@ -36,6 +37,7 @@ "react-i18next": "^16.1.0", "react-native": "0.81.5", "react-native-get-random-values": "^2.0.0", + "react-native-localization-settings": "^1.2.0", "react-native-mmkv": "^3.3.3", "react-native-nitro-modules": "^0.30.2", "react-native-reanimated": "~4.1.2", @@ -48,6 +50,7 @@ "react-native-worklets": "0.5.1", "react-tooltip": "^5.29.1", "sweetalert2": "^11.26.3", + "tsx": "^4.20.6", "uuid": "^13.0.0", "video.js": "^8.23.4", "yoshiki": "1.2.14", @@ -271,6 +274,58 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "@expo/cli": ["@expo/cli@54.0.12", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@expo/code-signing-certificates": "^0.0.5", "@expo/config": "~12.0.10", "@expo/config-plugins": "~54.0.2", "@expo/devcert": "^1.1.2", "@expo/env": "~2.0.7", "@expo/image-utils": "^0.8.7", "@expo/json-file": "^10.0.7", "@expo/mcp-tunnel": "~0.0.7", "@expo/metro": "~54.1.0", "@expo/metro-config": "~54.0.7", "@expo/osascript": "^2.3.7", "@expo/package-manager": "^1.9.8", "@expo/plist": "^0.4.7", "@expo/prebuild-config": "^54.0.5", "@expo/schema-utils": "^0.1.7", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.81.4", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "expo-server": "^1.0.2", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.1", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.4.3", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-aBwpzG8z5U4b51S3T5MRIRe+NOOW2KdJ7cvJD8quL2Ba9gZRw8UVb+pmL28tS9yL3r1r3n8b1COSaJ8Y0eRTFA=="], "@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.5", "", { "dependencies": { "node-forge": "^1.2.1", "nullthrows": "^1.1.1" } }, "sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw=="], @@ -781,6 +836,8 @@ "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], @@ -897,6 +954,8 @@ "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + "getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="], "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -927,6 +986,8 @@ "i18next": ["i18next@25.6.0", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw=="], + "i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="], + "i18next-http-backend": ["i18next-http-backend@3.0.2", "", { "dependencies": { "cross-fetch": "4.0.0" } }, "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -1259,6 +1320,8 @@ "react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.2.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q=="], + "react-native-localization-settings": ["react-native-localization-settings@1.2.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-pxX/mfokqjwIdb1zINuN6DLL4PeVHTaIGz2Tk833tS94fmpsSuPoYnkCmtXsfvZjxhDOSsRceao/JutJbIlpIQ=="], + "react-native-mmkv": ["react-native-mmkv@3.3.3", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-GMsfOmNzx0p5+CtrCFRVtpOOMYNJXuksBVARSQrCFaZwjUyHJdQzcN900GGaFFNTxw2fs8s5Xje//RDKj9+PZA=="], "react-native-nitro-modules": ["react-native-nitro-modules@0.30.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-+/uVS7FQwOiKYZQERMIvBRv5/X3CVHrFG6Nr/kIhVfVxGeUimHnBz7cgA97lJKIn7AKDRWL+UjLedW8pGOt0dg=="], @@ -1313,6 +1376,8 @@ "resolve-global": ["resolve-global@1.0.0", "", { "dependencies": { "global-dirs": "^0.1.1" } }, "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "resolve-workspace-root": ["resolve-workspace-root@2.0.0", "", {}, "sha512-IsaBUZETJD5WsI11Wt8PKHwaIe45or6pwNc8yflvLJ4DWtImK9kuLoH5kUva/2Mmx/RdIyr4aONNSa2v9LTJsw=="], "resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="], @@ -1447,6 +1512,8 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tsx": ["tsx@4.20.6", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg=="], + "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], diff --git a/front/package.json b/front/package.json index fccb6740..271181b8 100644 --- a/front/package.json +++ b/front/package.json @@ -39,6 +39,7 @@ "expo-splash-screen": "^31.0.10", "expo-status-bar": "~3.0.8", "expo-updates": "~29.0.11", + "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", "jassub": "^1.8.6", "langmap": "^0.0.16", @@ -47,6 +48,7 @@ "react-i18next": "^16.1.0", "react-native": "0.81.5", "react-native-get-random-values": "^2.0.0", + "react-native-localization-settings": "^1.2.0", "react-native-mmkv": "^3.3.3", "react-native-nitro-modules": "^0.30.2", "react-native-reanimated": "~4.1.2", @@ -59,6 +61,7 @@ "react-native-worklets": "0.5.1", "react-tooltip": "^5.29.1", "sweetalert2": "^11.26.3", + "tsx": "^4.20.6", "uuid": "^13.0.0", "video.js": "^8.23.4", "yoshiki": "1.2.14", diff --git a/front/packages/ui/src/settings/general.tsx b/front/packages/ui/src/settings/general.tsx deleted file mode 100644 index 45ba61ed..00000000 --- a/front/packages/ui/src/settings/general.tsx +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -import { deleteData, setUserTheme, storeData, useUserTheme } from "@kyoo/models"; -import { Link, Select } from "@kyoo/primitives"; -import { useTranslation } from "react-i18next"; -import { Preference, SettingsContainer } from "./base"; - -import Theme from "@material-symbols/svg-400/outlined/dark_mode.svg"; -import Language from "@material-symbols/svg-400/outlined/language.svg"; - -import Android from "@material-symbols/svg-400/rounded/android.svg"; -import Public from "@material-symbols/svg-400/rounded/public.svg"; -import { useLanguageName } from "../utils"; - -export const GeneralSettings = () => { - const { t, i18n } = useTranslation(); - const theme = useUserTheme("auto"); - const getLanguageName = useLanguageName(); - - const changeLanguage = (lang: string) => { - if (lang === "system") { - i18n.changeLanguage(i18n.systemLanguage); - deleteData("language"); - return; - } - storeData("language", lang); - i18n.changeLanguage(lang); - }; - - return ( - - - changeLanguage(value)} - values={["system", ...Object.keys(i18n.options.resources!)]} - getLabel={(key) => - key === "system" ? t("settings.general.language.system") : (getLanguageName(key) ?? key) - } - /> - - - ); -}; - -export const About = () => { - const { t } = useTranslation(); - - return ( - - - - - - - - - ); -}; diff --git a/front/packages/ui/src/settings/index.tsx b/front/packages/ui/src/settings/index.tsx deleted file mode 100644 index de60c769..00000000 --- a/front/packages/ui/src/settings/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -import { type QueryPage, useAccount } from "@kyoo/models"; -import { ts } from "@kyoo/primitives"; -import { ScrollView } from "react-native"; -import { DefaultLayout } from "../layout"; -import { AccountSettings } from "./account"; -import { About, GeneralSettings } from "./general"; -import { OidcSettings } from "./oidc"; -import { PlaybackSettings } from "./playback"; - -export const SettingsPage: QueryPage = () => { - const account = useAccount(); - return ( - - - {account && } - {account && } - {account && } - - - ); -}; - -SettingsPage.getLayout = DefaultLayout; -SettingsPage.getFetchUrls = () => [OidcSettings.query()]; diff --git a/front/packages/ui/src/settings/oidc.tsx b/front/packages/ui/src/settings/oidc.tsx deleted file mode 100644 index e4c383e5..00000000 --- a/front/packages/ui/src/settings/oidc.tsx +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -import { - type QueryIdentifier, - type ServerInfo, - ServerInfoP, - queryFn, - useAccount, - useFetch, -} from "@kyoo/models"; -import { Button, IconButton, Link, Skeleton, tooltip, ts } from "@kyoo/primitives"; -import { useTranslation } from "react-i18next"; -import { ImageBackground } from "react-native"; -import { rem, useYoshiki } from "yoshiki/native"; -import { ErrorView } from "../../../../src/ui/errors"; -import { Preference, SettingsContainer } from "./base"; - -import Badge from "@material-symbols/svg-400/outlined/badge.svg"; -import Remove from "@material-symbols/svg-400/outlined/close.svg"; -import OpenProfile from "@material-symbols/svg-400/outlined/open_in_new.svg"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; - -export const OidcSettings = () => { - const account = useAccount()!; - const { css } = useYoshiki(); - const { t } = useTranslation(); - const { data, error } = useFetch(OidcSettings.query()); - const queryClient = useQueryClient(); - const { mutateAsync: unlinkAccount } = useMutation({ - mutationFn: async (provider: string) => - await queryFn({ - path: ["auth", "login", provider], - method: "DELETE", - }), - onSettled: async () => await queryClient.invalidateQueries({ queryKey: ["auth", "me"] }), - }); - - return ( - - {error ? ( - - ) : data ? ( - Object.entries(data.oidc).map(([id, x]) => { - const acc = account.externalId[id]; - return ( - - ) - } - > - {acc ? ( - <> - {acc.profileUrl && ( - - )} - unlinkAccount(id)} - {...tooltip(t("settings.oidc.delete", { provider: x.displayName }))} - /> - - ) : ( -