File size: 6,773 Bytes
72f0edb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import React, { useEffect, useState, useRef } from "react";
import { useParams, useNavigate } from "react-router-dom";
import Layout from "@/components/layout/Layout";
import Header from "../components/Header";
import { useUrdf } from "@/hooks/useUrdfData";
import { toast } from "sonner";
import { getImageUrl } from "@/api/urdfApi";
import { useUrdf as useUrdfContext } from "@/hooks/useUrdf";
import { downloadAndExtractZip } from "@/lib/UrdfDragAndDrop";
import { supabase } from "@/integrations/supabase/client";
import { Loader2 } from "lucide-react";

// This is needed to make TypeScript recognize webkitdirectory as a valid attribute
declare module "react" {
  interface InputHTMLAttributes<T> extends React.HTMLAttributes<T> {
    directory?: string;
    webkitdirectory?: string;
  }
}

const ContentDetail: React.FC = () => {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const { data: content, isLoading, error } = useUrdf(id || "");
  const [imageUrl, setImageUrl] = useState<string>("/placeholder.svg");
  const { urdfProcessor, processUrdfFiles, currentRobotData } =
    useUrdfContext();
  const [isLoadingUrdf, setIsLoadingUrdf] = useState(false);
  // Reference to track if we've already loaded this model
  const hasModelBeenLoaded = useRef(false);
  // State to track when the model is fully loaded and ready to display
  const [isModelReady, setIsModelReady] = useState(false);

  // If error occurred during fetch, show error and redirect
  useEffect(() => {
    if (error) {
      toast.error("Error loading robot details");
      navigate("/");
    }
  }, [error, navigate]);

  // If content not found and not loading, redirect to home
  useEffect(() => {
    if (!content && !isLoading && !error) {
      toast.error("Robot not found");
      navigate("/");
    }
  }, [content, isLoading, error, navigate]);

  // Fetch the image when content is loaded
  useEffect(() => {
    if (content?.imageUrl) {
      const fetchImage = async () => {
        const url = await getImageUrl(content.imageUrl);
        setImageUrl(url);
      };
      fetchImage();
    }
  }, [content]);

  // Reset the model states when the ID changes
  useEffect(() => {
    hasModelBeenLoaded.current = false;
    setIsModelReady(false);
  }, [id]);

  // Check if we already have this model loaded
  useEffect(() => {
    if (content && currentRobotData?.name === content.title) {
      // The model is already loaded
      hasModelBeenLoaded.current = true;
      setIsModelReady(true);
      console.log("Model already loaded and ready to display");
    }
  }, [content, currentRobotData]);

  // Load the URDF model automatically when the content details are loaded
  useEffect(() => {
    const loadUrdfModel = async () => {
      // Only load if we have content, a processor, not currently loading,
      // and haven't already loaded this model
      if (
        content?.urdfPath &&
        urdfProcessor &&
        !isLoadingUrdf &&
        !hasModelBeenLoaded.current
      ) {
        // Mark that we've attempted to load this model
        hasModelBeenLoaded.current = true;
        setIsLoadingUrdf(true);
        setIsModelReady(false); // Reset model ready state while loading

        console.log(`Auto-loading URDF model for ${content.title}...`);

        const loadingToast = toast.loading(`Loading ${content.title}...`, {
          description: "Downloading and extracting URDF model",
        });

        try {
          // Get the actual URL for the zip file
          let zipUrl = content.urdfPath;

          // If it's a storage path and not a full URL, get a signed URL
          if (!zipUrl.startsWith("http")) {
            const { data, error } = await supabase.storage
              .from("robotbucket")
              .createSignedUrl(zipUrl, 3600); // 1 hour expiry

            if (error) {
              throw new Error(
                `Failed to get URL for zip file: ${error.message}`
              );
            }

            zipUrl = data.signedUrl;
          }

          // Download and extract the zip file
          const { files, availableModels } = await downloadAndExtractZip(
            zipUrl,
            urdfProcessor
          );

          // Dismiss loading toast
          toast.dismiss(loadingToast);

          // If successful, process the extracted files similar to drag and drop
          if (files && availableModels.length > 0) {
            await processUrdfFiles(files, availableModels);
            toast.success(`Loaded model: ${content.title}`, {
              description: "URDF model ready for viewing",
            });

            // Set a short timeout to ensure the URDF context is fully updated
            setTimeout(() => {
              setIsModelReady(true);
            }, 1000);
          } else {
            toast.error("No URDF models found in the zip file");
          }
        } catch (error) {
          // Dismiss loading toast and show error
          toast.dismiss(loadingToast);
          console.error("Error processing URDF zip:", error);
          toast.error("Failed to load URDF model", {
            description:
              error instanceof Error ? error.message : "Unknown error",
          });
        } finally {
          setIsLoadingUrdf(false);
        }
      }
    };

    loadUrdfModel();
  }, [content, urdfProcessor, processUrdfFiles, isLoadingUrdf]);

  // If still loading content data, show initial loading state
  if (isLoading || !content) {
    return (
      <div className="min-h-screen bg-netflix-background flex items-center justify-center">
        <div className="text-white text-xl">Loading robot details...</div>
      </div>
    );
  }

  // // If content is loaded but URDF model is still loading or processing, show URDF loading state
  // if (!isModelReady || isLoadingUrdf) {
  //   return (
  //     <div className="min-h-screen bg-netflix-background flex flex-col items-center justify-center">
  //       <Loader2 className="h-12 w-12 text-white animate-spin mb-4" />
  //       <div className="text-white text-xl">
  //         Loading {content.title} model...
  //       </div>
  //       <p className="text-gray-400 mt-2">
  //         Please wait while we prepare the 3D model
  //       </p>
  //     </div>
  //   );
  // }

  // Only render the full layout once the model is ready
  return (
    <div className="flex flex-col h-screen bg-netflix-background text-white overflow-hidden">
      {/* Layout taking full height */}
      <div className="w-full h-full">
        <Layout />
      </div>

      {/* Header absolutely positioned at the top */}
      <div className="absolute top-0 left-0 right-0 z-50">
        <Header />
      </div>
    </div>
  );
};

export default ContentDetail;