Skip to content

Instantly share code, notes, and snippets.

@sean-ocallahan
Created February 18, 2025 20:54
Show Gist options
  • Save sean-ocallahan/48bed44902c0bc7eda6de42af14d9d25 to your computer and use it in GitHub Desktop.
Save sean-ocallahan/48bed44902c0bc7eda6de42af14d9d25 to your computer and use it in GitHub Desktop.
smplrspace v2.26 + next.js 14
"use client";
import { useEffect } from "react";
import { type Space } from "@smplrspace/smplr-loader";
import { env } from "@/env.mjs";
import { useSmplr } from "@/providers";
type FloorPlanViewerProps = {
floorPlanId: string;
onViewerReady: ({ space }: { space: Space }) => void;
onViewerResize: (dimensions: DOMRect) => void;
renderAnnotations: boolean;
};
/**
* Responsible for initializing the interactive Viewer. The resulting smplr client and query client are
* passed back to the `FloorPlan` container via the `onViewerReady` callback.
*/
export const FloorPlanViewer = ({
floorPlanId,
onViewerReady,
onViewerResize,
renderAnnotations = false,
}: FloorPlanViewerProps) => {
const { client } = useSmplr();
useEffect(() => {
if (!client) return;
const space = new client.Space({
spaceId: floorPlanId,
clientToken: env.NEXT_PUBLIC_SMPLR_CLIENT_TOKEN,
containerId: "floor-plan-container",
});
space.startViewer({
mode: "2d",
preview: false,
renderOptions: {
objects: true,
backgroundColor: "#fff",
annotations: renderAnnotations,
},
hideNavigationButtons: true,
loadingMessage: "Loading floor plan...",
onError: (error) => console.error("Could not start viewer", error),
onReady: () => {
onViewerReady({ space });
},
onResize: (data) => {
onViewerResize(data);
},
});
}, [client, floorPlanId, onViewerReady, onViewerResize, renderAnnotations]);
return <div key={floorPlanId} id="floor-plan-container" style={{ height: "100%" }} />;
};
import { SmplrProvider } from "./providers";
export default async function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="relative flex min-h-screen flex-col">
<main>
<SmplrProvider>
<div className="container relative">{children}</div>
</SmplrProvider>
</main>
<Footer />
</div>
);
}
"use client";
import { createContext, useContext, useEffect, useState } from "react";
import { type Smplr, loadSmplrJs } from "@smplrspace/smplr-loader";
import { type QueryClient as SmplrQueryClient } from "@smplrspace/smplr-loader/dist/generated/smplr";
import { env } from "@/env.mjs";
type SmplrContextType = {
client: Smplr | null;
smplrQueryClient: SmplrQueryClient | null;
};
export const SmplrContext = createContext<SmplrContextType>({
client: null,
smplrQueryClient: null,
});
/**
* Stores the current window smplr client and query client in context state.
*
* Data is accessible via the `useSmplr` hook.
*/
export function SmplrProvider({ children }: { children: React.ReactNode }) {
const [client, setClient] = useState<Smplr | null>(null);
const [smplrQueryClient, setSmplrQueryClient] = useState<SmplrQueryClient | null>(null);
/**
* Load the smplr sdk and create a new query client instance.
*
* @see - https://docs.smplrspace.com/#use-our-npm-package
*
* Note: Specifying the 'umd' bundle type is the only way to load the sdk at
* the moment. The default 'esm' bundle is unable to reliably load the sdk.
*/
useEffect(() => {
if (typeof window === "undefined") return;
loadSmplrJs("umd")
.then((client) => {
const queryClient = new client.QueryClient({
organizationId: env.NEXT_PUBLIC_SMPLR_ORG_ID,
clientToken: env.NEXT_PUBLIC_SMPLR_CLIENT_TOKEN,
});
setClient(client);
setSmplrQueryClient(queryClient);
})
.catch((error) => {
console.error("Failed to load the smplrspace sdk", error);
});
}, []);
return (
<SmplrContext.Provider value={{ client, smplrQueryClient }}>{children}</SmplrContext.Provider>
);
}
export function useSmplr() {
const ctx = useContext(SmplrContext);
if (!ctx) {
throw new Error("useSmplr must be used within a SmplrProvider");
}
return ctx;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment