enzostvs HF Staff commited on
Commit
ddb7f1c
·
1 Parent(s): 718ae59
app/(public)/projects/page.tsx CHANGED
@@ -3,10 +3,7 @@ import { MyProjects } from "@/components/my-projects";
3
  import { NotLogged } from "@/components/not-logged/not-logged";
4
 
5
  export default async function ProjectsPage() {
6
- const { ok, projects } = await getProjects();
7
- if (!ok) {
8
- return <NotLogged />;
9
- }
10
 
11
- return <MyProjects projects={projects} />;
12
  }
 
3
  import { NotLogged } from "@/components/not-logged/not-logged";
4
 
5
  export default async function ProjectsPage() {
6
+ // const { ok, projects } = await getProjects();
 
 
 
7
 
8
+ return <MyProjects />;
9
  }
app/api/me/route.ts CHANGED
@@ -1,3 +1,4 @@
 
1
  import { headers } from "next/headers";
2
  import { NextResponse } from "next/server";
3
 
@@ -21,5 +22,26 @@ export async function GET() {
21
  );
22
  }
23
  const user = await userResponse.json();
24
- return NextResponse.json({ user, errCode: null }, { status: 200 });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
 
1
+ import { listSpaces } from "@huggingface/hub";
2
  import { headers } from "next/headers";
3
  import { NextResponse } from "next/server";
4
 
 
22
  );
23
  }
24
  const user = await userResponse.json();
25
+ const projects = [];
26
+ for await (const space of listSpaces({
27
+ accessToken: token.replace("Bearer ", "") as string,
28
+ additionalFields: ["author", "cardData"],
29
+ search: {
30
+ owner: user.name,
31
+ }
32
+ })) {
33
+ if (
34
+ !space.private &&
35
+ space.sdk === "static" &&
36
+ Array.isArray((space.cardData as { tags?: string[] })?.tags) &&
37
+ (
38
+ ((space.cardData as { tags?: string[] })?.tags?.includes("deepsite-v3")) ||
39
+ ((space.cardData as { tags?: string[] })?.tags?.includes("deepsite"))
40
+ )
41
+ ) {
42
+ projects.push(space);
43
+ }
44
+ }
45
+
46
+ return NextResponse.json({ user, projects, errCode: null }, { status: 200 });
47
  }
app/layout.tsx CHANGED
@@ -72,16 +72,16 @@ export const viewport: Viewport = {
72
  async function getMe() {
73
  const cookieStore = await cookies();
74
  const token = cookieStore.get(MY_TOKEN_KEY())?.value;
75
- if (!token) return { user: null, errCode: null };
76
  try {
77
  const res = await apiServer.get("/me", {
78
  headers: {
79
  Authorization: `Bearer ${token}`,
80
  },
81
  });
82
- return { user: res.data.user, errCode: null };
83
  } catch (err: any) {
84
- return { user: null, errCode: err.status };
85
  }
86
  }
87
 
 
72
  async function getMe() {
73
  const cookieStore = await cookies();
74
  const token = cookieStore.get(MY_TOKEN_KEY())?.value;
75
+ if (!token) return { user: null, projects: [], errCode: null };
76
  try {
77
  const res = await apiServer.get("/me", {
78
  headers: {
79
  Authorization: `Bearer ${token}`,
80
  },
81
  });
82
+ return { user: res.data.user, projects: res.data.projects, errCode: null };
83
  } catch (err: any) {
84
+ return { user: null, projects: [], errCode: err.status };
85
  }
86
  }
87
 
components/contexts/app-context.tsx CHANGED
@@ -5,7 +5,7 @@ import { toast } from "sonner";
5
  import { usePathname, useRouter } from "next/navigation";
6
 
7
  import { useUser } from "@/hooks/useUser";
8
- import { User } from "@/types";
9
  import { useBroadcastChannel } from "@/lib/useBroadcastChannel";
10
 
11
  export default function AppContext({
@@ -15,6 +15,7 @@ export default function AppContext({
15
  children: React.ReactNode;
16
  me?: {
17
  user: User | null;
 
18
  errCode: number | null;
19
  };
20
  }) {
 
5
  import { usePathname, useRouter } from "next/navigation";
6
 
7
  import { useUser } from "@/hooks/useUser";
8
+ import { ProjectType, User } from "@/types";
9
  import { useBroadcastChannel } from "@/lib/useBroadcastChannel";
10
 
11
  export default function AppContext({
 
15
  children: React.ReactNode;
16
  me?: {
17
  user: User | null;
18
+ projects: ProjectType[];
19
  errCode: number | null;
20
  };
21
  }) {
components/editor/ask-ai/index.tsx CHANGED
@@ -28,6 +28,7 @@ import { useLoginModal } from "@/components/contexts/login-context";
28
  import { Settings } from "./settings";
29
  import { useProModal } from "@/components/contexts/pro-context";
30
  import { MODELS } from "@/lib/providers";
 
31
 
32
  export const AskAi = ({
33
  project,
@@ -39,7 +40,7 @@ export const AskAi = ({
39
  isNew?: boolean;
40
  onScrollToBottom?: () => void;
41
  }) => {
42
- const { user } = useUser();
43
  const { currentPageData, isUploading, pages, isLoadingProject } = useEditor();
44
  const {
45
  isAiWorking,
@@ -86,6 +87,8 @@ export const AskAi = ({
86
 
87
  const callAi = async (redesignMarkdown?: string) => {
88
  if (!user) return openLoginModal();
 
 
89
  if (isAiWorking) return;
90
  if (!redesignMarkdown && !prompt.trim()) return;
91
 
 
28
  import { Settings } from "./settings";
29
  import { useProModal } from "@/components/contexts/pro-context";
30
  import { MODELS } from "@/lib/providers";
31
+ import { MAX_FREE_PROJECTS } from "@/lib/utils";
32
 
33
  export const AskAi = ({
34
  project,
 
40
  isNew?: boolean;
41
  onScrollToBottom?: () => void;
42
  }) => {
43
+ const { user, projects } = useUser();
44
  const { currentPageData, isUploading, pages, isLoadingProject } = useEditor();
45
  const {
46
  isAiWorking,
 
87
 
88
  const callAi = async (redesignMarkdown?: string) => {
89
  if (!user) return openLoginModal();
90
+ if (!user.isPro && projects.length >= MAX_FREE_PROJECTS)
91
+ return openProModal([]);
92
  if (isAiWorking) return;
93
  if (!redesignMarkdown && !prompt.trim()) return;
94
 
components/my-projects/index.tsx CHANGED
@@ -12,23 +12,22 @@ import { ProTag } from "@/components/pro-modal";
12
  import { Button } from "@/components/ui/button";
13
  import { useProModal } from "@/components/contexts/pro-context";
14
  import { api } from "@/lib/api";
 
15
 
16
- export function MyProjects({
17
- projects: initialProjects,
18
- }: {
19
- projects: ProjectType[];
20
- }) {
21
- const { user } = useUser();
22
  const { openProModal } = useProModal();
23
- const [projects, setProjects] = useState<ProjectType[]>(
24
- initialProjects || []
25
- );
 
26
 
27
  const onDelete = async (project: ProjectType) => {
28
  const response = await api.delete(`/me/projects/${project.name}`);
29
  if (response.data.ok) {
30
  toast.success("Project deleted successfully!");
31
- setProjects((prev) => prev.filter((p) => p.id !== project.id));
 
32
  } else {
33
  toast.error(response.data.error);
34
  }
 
12
  import { Button } from "@/components/ui/button";
13
  import { useProModal } from "@/components/contexts/pro-context";
14
  import { api } from "@/lib/api";
15
+ import { NotLogged } from "../not-logged/not-logged";
16
 
17
+ export function MyProjects() {
18
+ const { user, projects, setProjects } = useUser();
 
 
 
 
19
  const { openProModal } = useProModal();
20
+
21
+ if (!user) {
22
+ return <NotLogged />;
23
+ }
24
 
25
  const onDelete = async (project: ProjectType) => {
26
  const response = await api.delete(`/me/projects/${project.name}`);
27
  if (response.data.ok) {
28
  toast.success("Project deleted successfully!");
29
+ const newProjects = projects.filter((p) => p.id !== project.id);
30
+ setProjects(newProjects);
31
  } else {
32
  toast.error(response.data.error);
33
  }
components/pro-modal/index.tsx CHANGED
@@ -24,7 +24,10 @@ export const ProModal = ({
24
  };
25
  return (
26
  <Dialog open={open} onOpenChange={onClose}>
27
- <DialogContent className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100">
 
 
 
28
  <DialogTitle className="hidden" />
29
  <main className="flex flex-col items-start text-left relative pt-2">
30
  <div className="flex items-center justify-start -space-x-4 mb-5">
@@ -72,6 +75,7 @@ export const ProModal = ({
72
  <Button
73
  variant="black"
74
  size="lg"
 
75
  className="w-full !text-base !h-11 mt-8"
76
  onClick={handleProClick}
77
  >
 
24
  };
25
  return (
26
  <Dialog open={open} onOpenChange={onClose}>
27
+ <DialogContent
28
+ showCloseButton={false}
29
+ className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100"
30
+ >
31
  <DialogTitle className="hidden" />
32
  <main className="flex flex-col items-start text-left relative pt-2">
33
  <div className="flex items-center justify-start -space-x-4 mb-5">
 
75
  <Button
76
  variant="black"
77
  size="lg"
78
+ tabIndex={-1}
79
  className="w-full !text-base !h-11 mt-8"
80
  onClick={handleProClick}
81
  >
hooks/useUser.ts CHANGED
@@ -4,7 +4,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
4
  import { useCookie } from "react-use";
5
  import { useRouter } from "next/navigation";
6
 
7
- import { User } from "@/types";
8
  import { api } from "@/lib/api";
9
  import { toast } from "sonner";
10
  import {
@@ -19,6 +19,7 @@ import {
19
  export const useUser = (initialData?: {
20
  user: User | null;
21
  errCode: number | null;
 
22
  }) => {
23
  const client = useQueryClient();
24
  const router = useRouter();
@@ -58,6 +59,18 @@ export const useUser = (initialData?: {
58
  client.setQueryData(["setLoadingAuth"], value);
59
  };
60
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  const openLoginWindow = async () => {
62
  setCurrentRoute(window.location.pathname);
63
 
@@ -119,12 +132,15 @@ export const useUser = (initialData?: {
119
  router.push("/");
120
  toast.success("Logout successful");
121
  client.invalidateQueries({ queryKey: ["user.me"] });
 
122
  window.location.reload();
123
  } catch (error) {
124
  console.error("Logout error:", error);
125
  clearAuthDataFallback();
126
  removeCurrentRoute();
127
  client.setQueryData(["user.me"], { user: null, errCode: null });
 
 
128
  router.push("/");
129
  toast.success("Logout successful");
130
  window.location.reload();
@@ -133,6 +149,8 @@ export const useUser = (initialData?: {
133
 
134
  return {
135
  user,
 
 
136
  errCode,
137
  loading: isLoading || loadingAuth,
138
  openLoginWindow,
 
4
  import { useCookie } from "react-use";
5
  import { useRouter } from "next/navigation";
6
 
7
+ import { ProjectType, User } from "@/types";
8
  import { api } from "@/lib/api";
9
  import { toast } from "sonner";
10
  import {
 
19
  export const useUser = (initialData?: {
20
  user: User | null;
21
  errCode: number | null;
22
+ projects: ProjectType[];
23
  }) => {
24
  const client = useQueryClient();
25
  const router = useRouter();
 
59
  client.setQueryData(["setLoadingAuth"], value);
60
  };
61
 
62
+ const { data: projects } = useQuery({
63
+ queryKey: ["me.projects"],
64
+ queryFn: async () => [],
65
+ refetchOnWindowFocus: false,
66
+ refetchOnReconnect: false,
67
+ refetchOnMount: false,
68
+ initialData: initialData?.projects || [],
69
+ });
70
+ const setProjects = (projects: ProjectType[]) => {
71
+ client.setQueryData(["me.projects"], projects);
72
+ };
73
+
74
  const openLoginWindow = async () => {
75
  setCurrentRoute(window.location.pathname);
76
 
 
132
  router.push("/");
133
  toast.success("Logout successful");
134
  client.invalidateQueries({ queryKey: ["user.me"] });
135
+ client.invalidateQueries({ queryKey: ["me.projects"] });
136
  window.location.reload();
137
  } catch (error) {
138
  console.error("Logout error:", error);
139
  clearAuthDataFallback();
140
  removeCurrentRoute();
141
  client.setQueryData(["user.me"], { user: null, errCode: null });
142
+ client.invalidateQueries({ queryKey: ["user.me"] });
143
+ client.invalidateQueries({ queryKey: ["me.projects"] });
144
  router.push("/");
145
  toast.success("Logout successful");
146
  window.location.reload();
 
149
 
150
  return {
151
  user,
152
+ projects,
153
+ setProjects,
154
  errCode,
155
  loading: isLoading || loadingAuth,
156
  openLoginWindow,