Browse Source

fix auth

Dev
mortezaei 1 week ago
parent
commit
3788408bb4
  1. 30
      package-lock.json
  2. 5
      src/app/api/proxy/route.ts
  3. 82
      src/app/intro/page.tsx
  4. 2
      src/app/new-match/page.tsx
  5. 10
      src/components/Componentes/fix-to-the-end.tsx
  6. 11
      src/components/Componentes/slider-page.tsx
  7. 17
      src/components/Componentes/slider-slide-one.tsx
  8. 27
      src/lib/auth-bridge.ts

30
package-lock.json

@ -136,6 +136,7 @@
"integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^8.0.0",
"@babel/generator": "^8.0.0",
@ -906,6 +907,7 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=20.19.0"
},
@ -954,6 +956,7 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=20.19.0"
}
@ -2231,7 +2234,6 @@
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.29.7",
"js-tokens": "^4.0.0",
@ -2247,7 +2249,6 @@
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
@ -2257,8 +2258,7 @@
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@testing-library/jest-dom": {
"version": "7.0.0",
@ -2337,8 +2337,7 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/chai": {
"version": "5.2.3",
@ -2392,6 +2391,7 @@
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@ -2402,6 +2402,7 @@
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@ -2412,6 +2413,7 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"dev": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@ -2547,7 +2549,6 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=8"
}
@ -2558,7 +2559,6 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
},
@ -2646,6 +2646,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.44",
"caniuse-lite": "^1.0.30001806",
@ -2828,8 +2829,7 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/dunder-proto": {
"version": "1.0.1",
@ -3240,6 +3240,7 @@
"integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@asamuzakjp/css-color": "^5.1.11",
"@asamuzakjp/dom-selector": "^7.1.1",
@ -3578,7 +3579,6 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@ -3773,6 +3773,7 @@
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@ -3814,7 +3815,6 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@ -3848,6 +3848,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -3857,6 +3858,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@ -3878,8 +3880,7 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/redent": {
"version": "3.0.0",
@ -4273,6 +4274,7 @@
"integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"lightningcss": "^1.33.0",
"picomatch": "^4.0.5",

5
src/app/api/proxy/route.ts

@ -131,7 +131,7 @@ function getRequestHeaders(request: NextRequest, targetUrl: URL) {
getCookieValue(cookieHeader, "token") ??
getCookieValue(cookieHeader, "auth_token");
if (cookieToken && cookieToken !== "NO_TOKEN") {
if (cookieToken && cookieToken !== "NO_TOKEN" && cookieToken.trim() !== "") {
headers.set("authorization", `Token ${cookieToken}`);
}
}
@ -143,8 +143,9 @@ function getRequestHeaders(request: NextRequest, targetUrl: URL) {
// Fall back to the development default token when nothing else provided auth.
if (!headers.has("authorization")) {
const isDevelopment = process.env.NODE_ENV !== "production";
const defaultToken = process.env.NEXT_PUBLIC_DEFAULT_TOKEN;
if (defaultToken && defaultToken !== "NO_TOKEN") {
if (isDevelopment && defaultToken && defaultToken !== "NO_TOKEN") {
headers.set("authorization", `Token ${defaultToken}`);
}
}

82
src/app/intro/page.tsx

@ -2,12 +2,11 @@
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { useState } from "react";
import Button from "@/components/Componentes/button";
import PageHeader from "@/components/Componentes/page-header";
import ReportActionsSheet from "@/components/Componentes/report-actions-sheet";
import VideoPlayer from "@/components/Componentes/video-player";
import type { MarriageProfileResponse } from "@/hooks/marriage/types";
import { useMarriageConfigQuery } from "@/hooks/marriage/use-marriage-config";
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
import { authBridge } from "@/lib/auth-bridge";
@ -15,8 +14,6 @@ import { getSubmitPath } from "@/lib/get-submit-path";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
const REDIRECT_SESSION_KEY = "redirect";
export default function Intro() {
const router = useRouter();
const { dictionary: t, locale } = useI18n();
@ -26,80 +23,10 @@ export default function Intro() {
});
const [isReportSheetOpen, setIsReportSheetOpen] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isCheckingRedirect, setIsCheckingRedirect] = useState(true);
const [isPlayerOpen, setIsPlayerOpen] = useState(false);
const isRedirectingRef = useRef(false);
const { data: config } = useMarriageConfigQuery();
useEffect(() => {
let isCancelled = false;
const redirectIfNeeded = async () => {
if (isRedirectingRef.current) {
return;
}
try {
const isAuthenticated = authBridge.isAuthenticated();
if (!isAuthenticated) {
if (!isCancelled) {
setIsCheckingRedirect(false);
}
return;
}
isRedirectingRef.current = true;
if (!isCancelled) {
setIsCheckingRedirect(true);
}
const profileResponse = profile ?? (await refetch()).data;
const nextPath = localizePath(getSubmitPath(profileResponse), locale);
if (typeof window !== "undefined") {
try {
window.sessionStorage.removeItem(REDIRECT_SESSION_KEY);
} catch (e) {
console.warn("sessionStorage is not accessible:", e);
}
}
if (!isCancelled) {
const currentPath =
typeof window !== "undefined" ? window.location.pathname : "";
if (currentPath === nextPath) {
setIsCheckingRedirect(false);
} else {
router.replace(nextPath);
}
return;
}
} catch (error) {
console.error("Error in redirectIfNeeded:", error);
if (!isCancelled) {
setIsCheckingRedirect(false);
}
} finally {
isRedirectingRef.current = false;
}
};
void redirectIfNeeded();
const unsubscribe = window.addFlutterResponseListener?.((event) => {
if (event.action === "login" && event.success) {
void redirectIfNeeded();
}
});
return () => {
isCancelled = true;
unsubscribe?.();
};
}, [locale, profile, refetch, router]);
const handleSubmit = async () => {
if (isSubmitting) {
return;
@ -111,7 +38,8 @@ export default function Intro() {
if (!authBridge.isAuthenticated()) {
const token = await authBridge.ensureToken();
if (!token) {
console.warn("No token from bridge – proceeding with fallback path");
console.warn("No token from bridge – login was not completed");
return;
}
}
@ -140,10 +68,6 @@ export default function Intro() {
}
};
if (isCheckingRedirect) {
return null;
}
return (
<div className="pt-[max(16px,calc(var(--safe-top)+8px))]">
{isReportSheetOpen && (

2
src/app/new-match/page.tsx

@ -501,7 +501,7 @@ export default function NewMatchPage() {
{profile?.can_edit_profile === false && (
<div
style={{ paddingBottom: `${16 + bottom}px` }}
className="fixed inset-x-0 bottom-0 z-20 mx-auto w-full max-w-[375px] bg-background/95 px-[17px] pt-3 pb-[16px] backdrop-blur-md"
className="fixed inset-x-0 bottom-0 z-20 mx-auto w-full sm:max-w-[375px] bg-background/95 px-[17px] pt-3 pb-[16px] backdrop-blur-md"
>
<div
className="inline-flex w-full items-center justify-center gap-2 rounded-[9px] border-none bg-[#D1D1D6] px-4 h-[52px] text-center text-[#747474] shadow-none"

10
src/components/Componentes/fix-to-the-end.tsx

@ -4,13 +4,19 @@ import type { ReactNode } from "react";
type FixToTheEndProps = {
children: ReactNode;
className?: string;
};
export function FixToTheEnd({ children }: FixToTheEndProps) {
export function FixToTheEnd({ children, className }: FixToTheEndProps) {
return (
<div
style={{ paddingBottom: "calc(16px + var(--safe-bottom))" }}
className="fixed inset-x-0 bottom-0 z-20 mx-auto w-full max-w-[375px] bg-[#F5F5F5]/95 px-[17px] pt-3 backdrop-blur-md"
className={[
"fixed inset-x-0 bottom-0 z-20 mx-auto w-full sm:max-w-[375px] bg-[#F5F5F5]/95 px-[17px] pt-3 backdrop-blur-md",
className,
]
.filter(Boolean)
.join(" ")}
>
{children}
</div>

11
src/components/Componentes/slider-page.tsx

@ -137,7 +137,16 @@ export default function SliderPage() {
<NavigationButton
icon="back"
iconLabel="Close slider"
onClick={() => router.back()}
onClick={() => {
if (typeof window !== "undefined") {
try {
window.sessionStorage.setItem("skip_intro_redirect", "true");
} catch (e) {
console.warn("sessionStorage is not accessible:", e);
}
}
router.back();
}}
/>
<nav
aria-label={`Slide ${activeSlide + 1} of ${displaySlideCount}`}

17
src/components/Componentes/slider-slide-one.tsx

@ -442,9 +442,24 @@ export function SliderSlideOneActions({
onAccept,
disabled,
}: SliderSlideOneActionsProps) {
const handleBack = () => {
if (typeof window !== "undefined") {
try {
window.sessionStorage.setItem("skip_intro_redirect", "true");
} catch (e) {
console.warn("sessionStorage is not accessible:", e);
}
}
};
return (
<div className="flex items-center gap-3 [&>a]:flex-1 [&>button]:flex-1">
<Button variant="outlined" arrowDirection="left" href="/intro">
<Button
variant="outlined"
arrowDirection="left"
href="/intro"
onClick={handleBack}
>
Back
</Button>
<Button

27
src/lib/auth-bridge.ts

@ -49,7 +49,8 @@ class AuthBridge {
const coinsCookie =
getClientCookie(COINS_COOKIE_NAME) ?? getClientCookie("habib_coins");
if (!token) {
if (!token || token === "NO_TOKEN" || token.trim() === "") {
this.token = null;
return false;
}
@ -232,12 +233,12 @@ class AuthBridge {
getClientCookie("habib_token") ??
sessionToken;
// Treat "NO_TOKEN" the same as having no cookie at all — fall through
// to the default token instead of returning null.
const effectiveCookie =
cookieToken && cookieToken !== "NO_TOKEN" ? cookieToken : null;
cookieToken && cookieToken !== "NO_TOKEN" && cookieToken.trim() !== ""
? cookieToken
: null;
if (this.token) {
if (this.token && this.token !== "NO_TOKEN" && this.token.trim() !== "") {
return this.token;
}
@ -245,10 +246,16 @@ class AuthBridge {
return effectiveCookie;
}
return (
process.env.NEXT_PUBLIC_DEFAULT_TOKEN ??
"f3a7543b44ef0a713d1ee0d4f7866b3825cf1308"
);
const isDevelopment = process.env.NODE_ENV !== "production";
if (
isDevelopment &&
process.env.NEXT_PUBLIC_DEFAULT_TOKEN &&
process.env.NEXT_PUBLIC_DEFAULT_TOKEN !== "NO_TOKEN"
) {
return process.env.NEXT_PUBLIC_DEFAULT_TOKEN;
}
return null;
}
public getCoins(): number {
@ -257,7 +264,7 @@ class AuthBridge {
public isAuthenticated(): boolean {
const token = this.getToken();
return !!token && token !== "NO_TOKEN";
return !!token && token !== "NO_TOKEN" && token.trim() !== "";
}
}

Loading…
Cancel
Save