diff --git a/next.config.mjs b/next.config.mjs
index 2ffa386..a649240 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,9 +1,6 @@
await import("./src/env.js");
const config = {
- experimental: {
- instrumentationHook: true
- },
output: process.env.STANDALONE_OUTPUT ? "standalone" : undefined,
images: {
remotePatterns: [
diff --git a/src/components/nodes/Library/Playlist.tsx b/src/components/nodes/Library/Playlist.tsx
index ee3f90d..58f2cf1 100644
--- a/src/components/nodes/Library/Playlist.tsx
+++ b/src/components/nodes/Library/Playlist.tsx
@@ -39,49 +39,26 @@ import { Separator } from "~/components/ui/separator";
import { CardWithHeader } from "../Primitives/Card";
import InputPrimitive from "../Primitives/Input";
-import * as z from "zod";
-
import { Form, FormField, FormItem, FormLabel } from "@/components/ui/form";
import useBasicNodeState from "~/hooks/useBasicNodeState";
+import { usePlaylistState } from "~/hooks/usePlaylistState";
import Debug from "../Primitives/Debug";
-import { PlaylistItem as PlaylistItemPrimitive } from "../Primitives/PlaylistItem";
+import PlaylistCommand from "../Primitives/PlaylistCommand";
+
type PlaylistProps = {
id: string;
// TODO type on playlist
data: Workflow.Playlist;
};
-const formSchema = z.object({
- playlistId: z.string().min(1, {
- message: "Playlist is required.",
- }),
- limit: z.number().optional(),
- offset: z.number().optional(),
-});
-
-const PlaylistItem = ({
- playlist,
- onSelect,
-}: {
- playlist: Workflow.Playlist;
- onSelect: () => void;
-}) => (
-
-
-
-);
-
const PlaylistComponent: React.FC = ({ id, data }) => {
- const [open, setOpen] = React.useState(false);
- const [selectedPlaylist, setSelectedPlaylist] =
- React.useState(data);
- const [search, setSearch] = React.useState("");
-
const {
+ open,
+ setOpen,
+ selectedPlaylist,
+ setSelectedPlaylist,
+ search,
+ setSearch,
state,
isValid,
targetConnections,
@@ -91,109 +68,11 @@ const PlaylistComponent: React.FC = ({ id, data }) => {
register,
getNodeData,
updateNodeData,
- } = useBasicNodeState(id, formSchema);
-
- const { session, userPlaylists, setUserPlaylistsStore } = useStore(
- (state) => ({
- session: state.session,
- userPlaylists: state.userPlaylists,
- setUserPlaylistsStore: state.setUserPlaylists,
- }),
- );
-
- React.useEffect(() => {
- if (data) {
- form?.setValue("playlistId", data.playlistId);
- updateNodeData(id, data);
- form?.trigger("playlistId");
- }
- }, [data, form, id, updateNodeData]);
-
- const watch = form!.watch();
- const prevWatchRef = React.useRef(watch);
- const prevSelectedPlaylistRef = React.useRef(selectedPlaylist);
-
- // biome-ignore lint/correctness/useExhaustiveDependencies:
- React.useEffect(() => {
- if (
- JSON.stringify(prevWatchRef.current) !== JSON.stringify(watch) ||
- JSON.stringify(prevSelectedPlaylistRef.current) !==
- JSON.stringify(selectedPlaylist)
- ) {
- updateNodeData(id, {
- ...watch,
- ...selectedPlaylist,
- });
- }
- prevWatchRef.current = watch;
- prevSelectedPlaylistRef.current = selectedPlaylist;
- }, [watch, selectedPlaylist, data, id, updateNodeData]);
-
- // biome-ignore lint/correctness/useExhaustiveDependencies:
- React.useEffect(() => {
- const searchPlaylist = async () => {
- if (search.length > 0) {
- try {
- const response = await fetch(
- `/api/user/${session.user.providerAccountId}/playlists?q=${search}`,
- );
- const data = await response.json();
- const newPlaylists = userPlaylists.concat(data);
- const dedupedPlaylists = newPlaylists.reduce((acc, current) => {
- const x = acc.find(
- (item) => item.playlistId === current.playlistId,
- );
- if (!x) {
- return acc.concat([current]);
- } else {
- return acc;
- }
- }, []);
-
- setUserPlaylistsStore(dedupedPlaylists);
- } catch (err) {
- console.error(err);
- }
- }
- };
-
- const userPlaylistsFetch = async () => {
- try {
- const response = await fetch(
- `/api/user/${session.user.providerAccountId}/playlists`,
- );
- const data = await response.json();
- setUserPlaylistsStore(data as any[]);
- } catch (err) {
- console.error(err);
- }
- };
-
- function setUserPlaylists() {
- if (search.length > 0) {
- searchPlaylist().catch((err) => {
- console.error(err);
- });
- } else {
- userPlaylistsFetch().catch((err) => {
- console.error(err);
- });
- }
- }
-
- // debounce({delay: 500}, setUserPlaylists)();
- setUserPlaylists();
- }, [search, session?.user?.providerAccountId, setUserPlaylistsStore]);
-
- const handleSelect = (playlist) => {
- console.info("handle select", playlist);
- form?.setValue("playlistId", playlist.playlistId, {
- shouldValidate: true,
- });
- console.info("data after update", getNodeData(id));
- setSelectedPlaylist(playlist as Workflow.Playlist);
- setOpen(false);
- };
+ session,
+ userPlaylists,
+ setUserPlaylistsStore,
+ handleSelect,
+ } = usePlaylistState(id, data);
return (
= ({ id, data }) => {
{userPlaylists.length > 0
? userPlaylists.map((playlist) => (
- handleSelect(playlist)}
diff --git a/src/components/nodes/Library/SaveAsAppend.tsx b/src/components/nodes/Library/SaveAsAppend.tsx
index 013191e..96856c8 100644
--- a/src/components/nodes/Library/SaveAsAppend.tsx
+++ b/src/components/nodes/Library/SaveAsAppend.tsx
@@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";
-import { Position, useHandleConnections } from "@xyflow/react";
-import React from "react";
+import { Position } from "@xyflow/react";
import NodeHandle from "../Primitives/NodeHandle";
import { ChevronsUpDown } from "lucide-react";
@@ -25,17 +24,14 @@ import {
import { ScrollArea } from "@/components/ui/scroll-area";
import Image from "next/image";
-import useStore from "~/app/states/store";
-import { CardWithHeader } from "../Primitives/Card";
-
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useForm } from "react-hook-form";
import * as z from "zod";
+import { CardWithHeader } from "../Primitives/Card";
import { Form, FormField, FormItem, FormLabel } from "@/components/ui/form";
+import { usePlaylistState } from "~/hooks/usePlaylistState";
import Debug from "../Primitives/Debug";
-import { PlaylistItem as PlaylistItemPrimitive } from "../Primitives/PlaylistItem";
+import PlaylistCommand from "../Primitives/PlaylistCommand";
type PlaylistProps = {
id: string;
@@ -48,132 +44,35 @@ const formSchema = z.object({
}),
});
-const PlaylistItem = ({
- playlist,
- onSelect,
-}: {
- playlist: Workflow.Playlist;
- onSelect: () => void;
-}) => (
-
-
-
-);
-
function SaveAsAppendComponent({ id, data }: PlaylistProps) {
- const [open, setOpen] = React.useState(false);
- const [selectedPlaylist, setSelectedPlaylist] =
- React.useState(data);
- const [search, setSearch] = React.useState("");
-
- const { session, updateNodeData, userPlaylists, nodes } = useStore(
- (state) => ({
- session: state.session,
- updateNodeData: state.updateNodeData,
- userPlaylists: state.userPlaylists,
- nodes: state.nodes,
- }),
- );
-
- const form = useForm({
- resolver: zodResolver(formSchema),
- mode: "all",
- shouldUnregister: false,
- });
- const { formState, register } = form;
-
- const TargetConnections = useHandleConnections({
- type: "target",
- });
- const SourceConnections = useHandleConnections({
- type: "source",
- });
-
- const watch = form.watch();
- const prevWatchRef = React.useRef(watch);
- const prevSelectedPlaylistRef = React.useRef(selectedPlaylist);
-
- // biome-ignore lint/correctness/useExhaustiveDependencies:
- React.useEffect(() => {
- if (data) {
- form?.setValue("playlistId", data.playlistId);
- updateNodeData(id, data);
- form?.trigger("playlistId");
-
- // Fetch playlist info
- fetch(`/api/user/@me/playlist/${data.playlistId}`)
- .then((response) => response.json())
- .then((playlist: Workflow.Playlist) => {
- setSelectedPlaylist(playlist);
- })
- .catch((error) => console.error("Error:", error));
- }
- }, []);
-
- React.useEffect(() => {
- if (
- JSON.stringify(prevWatchRef.current) !== JSON.stringify(watch) ||
- JSON.stringify(prevSelectedPlaylistRef.current) !==
- JSON.stringify(selectedPlaylist)
- ) {
- updateNodeData(id, {
- id: watch.playlistId,
- ...watch,
- ...selectedPlaylist,
- });
- }
- prevWatchRef.current = watch;
- prevSelectedPlaylistRef.current = selectedPlaylist;
- }, [id, watch, selectedPlaylist, updateNodeData]);
-
- React.useEffect(() => {
- const userPlaylists = async () => {
- try {
- const response = await fetch(
- `/api/user/${session.user.providerAccountId}/playlists`,
- );
- const data = await response.json();
- useStore.setState({ userPlaylists: data });
- } catch (err) {
- console.error(err);
- }
- };
-
- // debounce({delay: 500}, setUserPlaylists)();
- userPlaylists()
- .then(() => {
- console.info("user playlists updated");
- })
- .catch((err) => {
- console.error(err);
- });
- }, [session.user.providerAccountId]);
-
- function getNodeData(id: string) {
- const node = nodes.find((node) => node.id === id);
- return node?.data;
- }
-
- const handleSelect = (playlist) => {
- console.info("handle select", playlist);
- form.setValue("playlistId", playlist.playlistId, {
- shouldValidate: true,
- });
- console.info("data after update", getNodeData(id));
- setSelectedPlaylist(playlist as Workflow.Playlist);
- setOpen(false);
- };
+ const {
+ open,
+ setOpen,
+ selectedPlaylist,
+ setSelectedPlaylist,
+ search,
+ setSearch,
+ state,
+ isValid,
+ targetConnections,
+ sourceConnections,
+ form,
+ formState,
+ register,
+ getNodeData,
+ updateNodeData,
+ session,
+ userPlaylists,
+ setUserPlaylistsStore,
+ handleSelect,
+ } = usePlaylistState(id, data);
return (
-