Browse Source

fix: improve keyboard interaction reliability, add SSR debugging logs, and resolve DiscountWidget initialization in subscription sheet

master
mortezaei 2 weeks ago
parent
commit
e575733579
  1. 20
      src/app/layout.tsx
  2. 2
      src/app/new-match/new-match-client.tsx
  3. 10
      src/app/providers.tsx
  4. 1
      src/app/request-accepted/request-accepted-client.tsx
  5. 6
      src/components/Componentes/discount-widget.tsx
  6. 31
      src/components/Componentes/information-sheet.test.tsx
  7. 12
      src/components/Componentes/information-sheet.tsx
  8. 4
      src/components/Componentes/subscription-required-sheet.tsx
  9. 6
      src/hooks/marriage/use-profile-main.ts

20
src/app/layout.tsx

@ -61,14 +61,32 @@ export default async function RootLayout({
const parsed = JSON.parse(decoded);
initialMarriageJson = decoded;
initialProfile = getInitialMarriageProfile(parsed);
console.log("🖥️ [SSR Layout] Parsed rawMarriageCookie successfully:", {
status: initialProfile?.status,
gender: initialProfile?.gender,
has_match_summary: Boolean(initialProfile?.match_summary),
match_summary_id: initialProfile?.match_summary?.id,
public_info_count: initialProfile?.match_summary?.public_info?.length,
});
} catch {
try {
const parsed = JSON.parse(rawMarriageCookie);
initialMarriageJson = rawMarriageCookie;
initialProfile = getInitialMarriageProfile(parsed);
} catch {}
console.log("🖥️ [SSR Layout] Parsed rawMarriageCookie (non-decoded) successfully:", {
status: initialProfile?.status,
gender: initialProfile?.gender,
has_match_summary: Boolean(initialProfile?.match_summary),
match_summary_id: initialProfile?.match_summary?.id,
public_info_count: initialProfile?.match_summary?.public_info?.length,
});
} catch (e) {
console.warn("🖥️ [SSR Layout] Failed to parse rawMarriageCookie:", e);
}
}
} else {
console.log("🖥️ [SSR Layout] No rawMarriageCookie found in request cookies");
}
return (
<html

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

@ -738,7 +738,7 @@ export default function NewMatchClient() {
</section>
{/* 2. Match Summary Card Section */}
<div className="w-full shrink-0">
<div className="w-full shrink-0" suppressHydrationWarning>
{(isLoading || (!matchSummary && isFetching)) ? (
<section className="relative overflow-hidden rounded-[24px] bg-[#FAFBFD] border border-[#F2E5E8] shadow-[0_4px_24px_rgba(0,0,0,0.04)] text-start">
<div className="relative h-[74px] w-full bg-[linear-gradient(180deg,#FCE2E6_0%,#FFD6DC_100%)]" />

10
src/app/providers.tsx

@ -44,7 +44,17 @@ export default function Providers({ children, initialProfile }: ProvidersProps)
},
});
if (initialProfile) {
console.log("⚡ [Providers] Initializing QueryClient cache with SSR initialProfile:", {
id: initialProfile.id,
status: initialProfile.status,
gender: initialProfile.gender,
has_match_summary: Boolean(initialProfile.match_summary),
match_summary_id: initialProfile.match_summary?.id,
public_info_count: initialProfile.match_summary?.public_info?.length,
});
qc.setQueryData(marriageQueryKeys.profile(), initialProfile);
} else {
console.log("ℹ️ [Providers] No initialProfile passed from SSR");
}
return qc;
},

1
src/app/request-accepted/request-accepted-client.tsx

@ -572,6 +572,7 @@ export default function RequestAcceptedClient() {
setPaymentError(null);
setIsInsufficientCoins(false);
}}
planId={recommendedPlanId}
onPayment={handlePayment}
isPaymentPending={!recommendedPlanId || paymentMutation.isPending}
errorMessage={paymentError}

6
src/components/Componentes/discount-widget.tsx

@ -157,12 +157,6 @@ export function DiscountWidget({
dir="auto"
value={code}
disabled={discountStatus === "loading" || discountResult !== null}
onFocus={(e) => {
const target = e.target;
setTimeout(() => {
target.scrollIntoView({ behavior: "smooth", block: "center" });
}, 150);
}}
onChange={(e) => {
setCode(e.target.value);
if (discountStatus !== "initial") {

31
src/components/Componentes/information-sheet.test.tsx

@ -100,5 +100,36 @@ describe("InformationSheet", () => {
expect(section?.style.paddingBottom).toBe("");
});
});
it("should immediately reset keyboard lift when input loses focus (focusOut)", async () => {
render(
<InformationSheet
isOpen={true}
title="Payment Sheet"
description={
<div>
<input type="text" placeholder="Enter code" data-testid="test-input-blur" />
</div>
}
/>,
);
const input = screen.getByTestId("test-input-blur");
const section = document.querySelector("section");
input.focus();
fireEvent.focusIn(input);
await waitFor(() => {
expect(section?.style.paddingBottom).not.toBe("");
});
input.blur();
fireEvent.focusOut(input);
await waitFor(() => {
expect(section?.style.paddingBottom).toBe("");
});
});
});

12
src/components/Componentes/information-sheet.tsx

@ -360,14 +360,6 @@ export function InformationSheet({
: getDefaultKeyboardHeight();
keyboardHeight = Math.max(keyboardHeight, expectedHeight);
setLift(keyboardHeight);
setTimeout(() => {
if (typeof (e.target as any)?.scrollIntoView === "function") {
(e.target as any).scrollIntoView({
behavior: "smooth",
block: "nearest",
});
}
}, 100);
}
};
@ -378,7 +370,7 @@ export function InformationSheet({
sheetRef.current?.contains(active) && isKeyboardInputTarget(active)
? (active as HTMLElement)
: null;
if (!activeInput && (viewPaddingsBridge.getConfig().keyboardHeight || 0) === 0) {
if (!activeInput) {
keyboardVisible = false;
keyboardHeight = 0;
setLift(0);
@ -445,7 +437,7 @@ export function InformationSheet({
const content = (
<div
className={[
"fixed inset-0 z-50 flex items-end justify-center overflow-y-auto",
"fixed inset-0 z-50 flex items-end justify-center overflow-hidden",
isClosing ? "flutter-scrim-exit" : "flutter-scrim",
]
.filter(Boolean)

4
src/components/Componentes/subscription-required-sheet.tsx

@ -97,13 +97,11 @@ export function SubscriptionRequiredSheet({
onClose={onClose}
buttons={({ close }) => (
<div className="space-y-3">
{planId ? (
<DiscountWidget
objectId={planId}
objectId={planId ?? 1}
onDiscountApplied={(res) => setAppliedDiscount(res)}
onDiscountCleared={() => setAppliedDiscount(null)}
/>
) : null}
{errorMessage && (
<div className="w-full bg-[#FEF2F2] text-[#B91C1C] text-xs p-3 rounded-[11px] text-center font-medium">

6
src/hooks/marriage/use-profile-main.ts

@ -40,13 +40,13 @@ export function getInitialMarriageProfile(
persistedPublicInfoCount: persisted?.match_summary?.public_info?.length,
});
// Priority 1: If Flutter provided match_summary (e.g. fresh match on new/current device) and persisted doesn't have it, prefer Flutter data
if (flutterData?.match_summary && !persisted?.match_summary) {
// Priority 1: If Flutter provided match_summary (e.g. active match from user/me), ALWAYS prefer Flutter data
if (flutterData?.match_summary) {
console.log("⚡ [getInitialMarriageProfile] Using Flutter initial data (has match_summary)");
return {
...flutterData,
id: flutterData.id || persisted?.id || 0,
status: flutterData.status || persisted?.status || "match_found",
status: flutterData.status || persisted?.status || "in_case",
};
}

Loading…
Cancel
Save