Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions client/src/app/[site]/components/Sidebar/SiteSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChevronDown, Plus } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import { useState, Suspense } from "react";
import { useGetSite, useGetSitesFromOrg } from "../../../../api/admin/sites";
import { Favicon } from "../../../../components/Favicon";
Expand All @@ -22,7 +22,6 @@ function SiteSelectorContent({ onSiteSelect }: { onSiteSelect: () => void }) {

const pathname = usePathname();
const router = useRouter();
const searchParams = useSearchParams();
const currentSiteId = Number(pathname.split("/")[1]);

const { user } = userStore();
Expand Down Expand Up @@ -57,8 +56,8 @@ function SiteSelectorContent({ onSiteSelect }: { onSiteSelect: () => void }) {
const pathSegments = pathname.split("/");
pathSegments[1] = site.siteId.toString();
const newPath = pathSegments.join("/");
const queryString = searchParams.toString();
router.push(queryString ? `${newPath}?${queryString}` : newPath);
const queryString = window.location.search;
router.push(queryString ? `${newPath}${queryString}` : newPath);
onSiteSelect(); // Close popover immediately
}}
className={cn(
Expand Down Expand Up @@ -101,8 +100,8 @@ function SiteSelectorContent({ onSiteSelect }: { onSiteSelect: () => void }) {
const pathSegments = pathname.split("/");
pathSegments[1] = site.siteId.toString();
const newPath = pathSegments.join("/");
const queryString = searchParams.toString();
router.push(queryString ? `${newPath}?${queryString}` : newPath);
const queryString = window.location.search;
router.push(queryString ? `${newPath}${queryString}` : newPath);
onSiteSelect(); // Close popover immediately
}}
className={cn(
Expand Down
10 changes: 6 additions & 4 deletions client/src/app/[site]/gsc/select-property/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"use client";

import { useSearchParams, useParams, useRouter } from "next/navigation";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";
import { authedFetch } from "@/api/utils";
import { useQueryState, parseAsJson } from "nuqs";

export default function SelectGSCPropertyPage() {
const searchParams = useSearchParams();
const params = useParams();
const router = useRouter();
const site = params.site as string;
Expand All @@ -19,8 +19,10 @@ export default function SelectGSCPropertyPage() {
const [isSubmitting, setIsSubmitting] = useState(false);

// Parse properties from query params
const propertiesParam = searchParams.get("properties");
const properties: string[] = propertiesParam ? JSON.parse(decodeURIComponent(propertiesParam)) : [];
const [properties] = useQueryState(
"properties",
parseAsJson<string[]>((value) => value as string[]).withDefault([])
);

const handleSubmit = async () => {
if (!selectedProperty) {
Expand Down
7 changes: 3 additions & 4 deletions client/src/app/[site]/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
"use client";

import { useSearchParams } from "next/navigation";
import { useQueryState, parseAsBoolean } from "nuqs";
import { useCurrentSite } from "../../api/admin/sites";

export const useEmbedablePage = () => {
const searchParams = useSearchParams();
const embed = searchParams.get("embed");
const [embed] = useQueryState("embed", parseAsBoolean);

const { subscription } = useCurrentSite();

if (embed === "true" && subscription?.planName !== "free") {
if (embed && subscription?.planName !== "free") {
return true;
}

Expand Down
52 changes: 19 additions & 33 deletions client/src/app/as/callback/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { motion } from "framer-motion";
import { ArrowRight, Check } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import React, { Suspense, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { addSite } from "../../../api/admin/sites";
import { useQueryStates, parseAsInteger, parseAsString } from "nuqs";
import { useSetPageTitle } from "../../../hooks/useSetPageTitle";
import { authClient } from "../../../lib/auth";
import { IS_CLOUD } from "../../../lib/const";
Expand All @@ -28,32 +29,6 @@ const contentVariants = {
visible: { opacity: 1, x: 0, transition: { duration: 0.3 } },
};

// Client component to handle AppSumo code from URL params
function AppSumoCodeHandler({
onSetCode,
onSetStep,
}: {
onSetCode: (code: string) => void;
onSetStep: (step: number) => void;
}) {
const searchParams = useSearchParams();

useEffect(() => {
const code = searchParams.get("code");
if (code) {
onSetCode(code);
}

// Handle step override for testing
const step = searchParams.get("step");
if (step && !isNaN(Number(step))) {
onSetStep(Number(step));
}
}, [searchParams, onSetCode, onSetStep]);

return null;
}

export default function AppSumoSignupPage() {
useSetPageTitle("Rybbit · AppSumo Signup");

Expand All @@ -63,6 +38,22 @@ export default function AppSumoSignupPage() {
const [appsumoCode, setAppsumoCode] = useState<string>("");
const router = useRouter();

// Get code and step from URL params
const [{ code, step: stepParam }] = useQueryStates({
code: parseAsString,
step: parseAsInteger,
});

// Sync URL params with local state
useEffect(() => {
if (code) {
setAppsumoCode(code);
}
if (stepParam && stepParam >= 1 && stepParam <= 3) {
setCurrentStep(stepParam);
}
}, [code, stepParam]);

// Step 1: Account creation
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
Expand Down Expand Up @@ -376,11 +367,6 @@ export default function AppSumoSignupPage() {
return (
<div className="flex justify-center items-center h-dvh w-full p-4 ">
<div className="flex flex-col items-center bg-background relative">
{/* Suspense boundary for the URL parameter handler */}
<Suspense fallback={null}>
<AppSumoCodeHandler onSetCode={setAppsumoCode} onSetStep={setCurrentStep} />
</Suspense>

{/* Background gradients similar to docs page */}
<div className="absolute top-0 left-0 w-[550px] h-[550px] bg-emerald-500/40 rounded-full blur-[80px] opacity-40"></div>
<div className="absolute top-20 left-20 w-[400px] h-[400px] bg-emerald-600/30 rounded-full blur-[70px] opacity-30"></div>
Expand Down
1 change: 0 additions & 1 deletion client/src/app/auth/subscription/success/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useSearchParams } from "next/navigation";

export default function StripeSuccessPage() {
const router = useRouter();
Expand Down
17 changes: 11 additions & 6 deletions client/src/app/invitation/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { AlertCircle } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";
import { Suspense, useState } from "react";
import { ThreeDotLoader } from "../../components/Loaders";
import { RybbitLogo } from "../../components/RybbitLogo";
Expand All @@ -12,10 +12,13 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/ui/ta
import { authClient } from "../../lib/auth";
import { Login } from "./components/login";
import { Signup } from "./components/signup";
import { useQueryStates, parseAsString } from "nuqs";

function AuthComponent() {
const organization = useSearchParams().get("organization");
const inviterEmail = useSearchParams().get("inviterEmail");
const [{ organization, inviterEmail }] = useQueryStates({
organization: parseAsString,
inviterEmail: parseAsString,
});
const [activeTab, setActiveTab] = useState<"login" | "signup">("signup");

return (
Expand Down Expand Up @@ -46,9 +49,11 @@ function AuthComponent() {
}

function AcceptInvitationInner() {
const invitationId = useSearchParams().get("invitationId");
const organization = useSearchParams().get("organization");
const inviterEmail = useSearchParams().get("inviterEmail");
const [{ invitationId, organization, inviterEmail }] = useQueryStates({
invitationId: parseAsString,
organization: parseAsString,
inviterEmail: parseAsString,
});
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string>("");
Expand Down
32 changes: 11 additions & 21 deletions client/src/app/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { Label } from "@/components/ui/label";
import { motion } from "framer-motion";
import { ArrowRight, Check } from "lucide-react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import React, { Suspense, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { addSite } from "../../api/admin/sites";
import { RybbitLogo, RybbitTextLogo } from "../../components/RybbitLogo";
import { useSetPageTitle } from "../../hooks/useSetPageTitle";
Expand All @@ -22,32 +22,27 @@ import { useConfigs } from "../../lib/configs";
import { IS_CLOUD } from "../../lib/const";
import { userStore } from "../../lib/userStore";
import { cn, isValidDomain, normalizeDomain } from "../../lib/utils";
import { useQueryState, parseAsInteger } from "nuqs";

// Animation variants for step transitions
const contentVariants = {
hidden: { opacity: 0, x: 20 },
visible: { opacity: 1, x: 0, transition: { duration: 0.3 } },
};

// Client component to handle step from URL params
function StepHandler({ onSetStep }: { onSetStep: (step: number) => void }) {
const searchParams = useSearchParams();

useEffect(() => {
const step = searchParams.get("step");
if (step && !isNaN(Number(step))) {
onSetStep(Number(step));
}
}, [searchParams, onSetStep]);

return null;
}

export default function SignupPage() {
const { configs, isLoading: isLoadingConfigs } = useConfigs();
useSetPageTitle("Rybbit · Signup");

const [currentStep, setCurrentStep] = useState(1);
const [stepParam] = useQueryState("step", parseAsInteger);

// Sync URL step param with local state on mount
useEffect(() => {
if (stepParam && stepParam >= 1 && stepParam <= 3) {
setCurrentStep(stepParam);
}
}, [stepParam]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string>("");
const router = useRouter();
Expand Down Expand Up @@ -380,11 +375,6 @@ export default function SignupPage() {
return (
<div className="flex justify-center items-center h-dvh w-full p-4 ">
<div className="flex flex-col items-center bg-background relative">
{/* Suspense boundary for the URL parameter handler */}
<Suspense fallback={null}>
<StepHandler onSetStep={setCurrentStep} />
</Suspense>

{/* Background gradients similar to docs page */}
{/* <div className="absolute top-0 left-0 w-[550px] h-[550px] bg-emerald-500/40 rounded-full blur-[80px] opacity-40"></div>
<div className="absolute top-20 left-20 w-[400px] h-[400px] bg-emerald-600/30 rounded-full blur-[70px] opacity-30"></div>
Expand Down
7 changes: 3 additions & 4 deletions client/src/components/SiteSettings/GSCManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,28 @@ import { ConfirmationModal } from "@/components/ConfirmationModal";
import { Button } from "@/components/ui/button";
import { SiGoogle } from "@icons-pack/react-simple-icons";
import { ExternalLink } from "lucide-react";
import { useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { useQueryState, parseAsString } from "nuqs";

interface GSCManagerProps {
disabled?: boolean;
}

export function GSCManager({ disabled = false }: GSCManagerProps) {
const searchParams = useSearchParams();
const [gscStatus] = useQueryState("gsc", parseAsString);
const { data: connection, isLoading, refetch } = useGSCConnection();
const { mutate: connect, isPending: isConnecting } = useConnectGSC();
const { mutate: disconnect, isPending: isDisconnecting } = useDisconnectGSC();
const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false);

// Check for OAuth success/error in URL params
useEffect(() => {
const gscStatus = searchParams.get("gsc");
if (gscStatus === "success") {
toast.success("Google Search Console connected successfully");
refetch();
}
}, [searchParams, refetch]);
}, [gscStatus, refetch]);

const handleDisconnect = async () => {
return new Promise((resolve, reject) => {
Expand Down
Loading
Loading