Skip to content

Commit

Permalink
UI changes
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavyagor12 committed Jun 29, 2024
1 parent d486e88 commit bb87c9e
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 111 deletions.
2 changes: 1 addition & 1 deletion packages/nextjs/app/api/imageToHtml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from "path";
import { html } from "satori-html";
import satori from "satori/wasm";

const robotoArrayBuffer = fs.readFileSync(path.resolve(process.cwd(), "public/fonts/roboto.ttf"));
const robotoArrayBuffer = fs.readFileSync(path.resolve(process.cwd(), "public/roboto.ttf"));

const createImageFromHtml = async (HTML: string) => {
const markup = html`${HTML}`;
Expand Down
30 changes: 2 additions & 28 deletions packages/nextjs/app/dashboard/[productID]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,20 @@
"use client";

import { FrameMetadataType } from "@coinbase/onchainkit";
import type { NextPage } from "next";
import FrameEditor from "~~/components/FrameEditor";
import FrameRender from "~~/components/FrameRenderer";
import FrameSidebar from "~~/components/FramesSidebar";
import { APP_URL } from "~~/constants";
import { ProvideProduct } from "~~/providers/ProductProvider";

const FrameExample: FrameMetadataType = {
buttons: [
{
label: `Vibes hai ye toh`,
},
{
action: "link",
label: "OnchainKit",
target: "https://onchainkit.xyz",
},
{
action: "post_redirect",
label: "Dog pictures",
},
],
image: {
src: `${APP_URL}/park-1.png`,
},
postUrl: `${APP_URL}/api/frame`,
state: {
time: new Date().toISOString(),
},
};

const Product: NextPage = () => {
return (
<ProvideProduct>
<div className="grid grid-cols-6 gap-4 pt-2">
<div className="col-span-1">
<FrameSidebar frames={[FrameExample, FrameExample, FrameExample, FrameExample]} />
<FrameSidebar />
</div>
<div className="col-span-3">
<FrameRender frame={FrameExample} />
<FrameRender />
</div>
<div className="col-span-2 ">
<FrameEditor />
Expand Down
22 changes: 12 additions & 10 deletions packages/nextjs/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import type { NextPage } from "next";
import ProductCard, { cardData } from "~~/components/ProductCard";
import ProductModal from "~~/components/ProductModal";
import ShopifyModal from "~~/components/ShopifyModal";
import { Journey } from "~~/types/commontypes";

const Dashboard: NextPage = () => {
const [open, setOpen] = useState(false);
const [shopify, setShopify] = useState(false);
const [products, setProducts] = useState([]);
const getAllProducts = async () => {
console.log("Fetching all products");
try {
const response = await fetch(`/api/journey`, {
method: "GET",
Expand All @@ -22,17 +23,18 @@ const Dashboard: NextPage = () => {
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log(data);
return response.json();
return data;
} catch (error: any) {
console.error(error);
throw new Error(error.message);
}
};

useEffect(() => {
getAllProducts();
});
getAllProducts().then(data => {
setProducts(data);
});
}, []);
return (
<div className="flex items-center flex-col flex-grow pt-10">
<div className="flex justify-end my-2 gap-4">
Expand All @@ -55,13 +57,13 @@ const Dashboard: NextPage = () => {
</div>
<div className="container">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2 sm:gap-4">
{cardData.map((journey: any) => (
{products.map((journey: Journey) => (
<ProductCard
key={journey.key}
id={journey.id}
key={journey._id}
id={journey._id}
name={journey.name}
image={journey.image}
description={journey.desc}
image={journey.image as string}
description={journey.desc as string}
/>
))}
</div>
Expand Down
94 changes: 63 additions & 31 deletions packages/nextjs/components/ButtonsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,101 @@ import { FrameButtonMetadata, FrameMetadataType } from "@coinbase/onchainkit";
import { IconButton } from "@mui/material";
import { PlusIcon } from "@heroicons/react/24/outline";
import { useProductJourney } from "~~/providers/ProductProvider";
import { saveFrame } from "~~/services/frames";
import { notification } from "~~/utils/scaffold-eth";

const ButtonList = () => {
const { frame: dbFrame } = useProductJourney();
const frame = dbFrame?.frameJson as FrameMetadataType;
console.log(frame);
const { currentFrame, setCurrentFrame, frame } = useProductJourney();

const [buttons, setButtons] = useState<FrameButtonMetadata[]>([{ label: "Button 1" }]);
const [activeButtonIndex, setActiveButtonIndex] = useState<number | null>(0);
const [activeButtonIndex, setActiveButtonIndex] = useState<number>(0);
useEffect(() => {
if (!frame) return;
setButtons(frame.buttons || [{ label: "Button 1" }]);
}, [frame]);
console.log("currentFrame", currentFrame);
console.log(activeButtonIndex);
console.log(currentFrame?.buttons[activeButtonIndex]);
}, [currentFrame, activeButtonIndex]);

if (!currentFrame) return null;
const handleAddButton = () => {
setButtons([...buttons, { label: `Button ${buttons.length + 1}` }]);
// @ts-ignore
setCurrentFrame(prevFrame => ({
...prevFrame,
buttons: [
...(prevFrame?.buttons || []),
{
label: "New Button",
postUrl: "",
target: "",
},
],
}));
};

const handleButtonClick = (index: number) => {
setActiveButtonIndex(index);
};

const handleSaveFrame = () => {
const handleSaveFrame = async () => {
notification.info("Frame saved successfully");
const updatedFrame = await saveFrame({
_id: frame?._id as string,
name: frame?.name as string,
frameJson: currentFrame as FrameMetadataType,
});
console.log(updatedFrame);
};

const handleSave = (button: FrameButtonMetadata) => {
if (currentFrame) {
// @ts-ignore
const newButtons = [...currentFrame.buttons];
newButtons[activeButtonIndex] = button;
setCurrentFrame({
...currentFrame,
// @ts-ignore
buttons: newButtons,
});
}
};

const handleDelete = () => {
if (!currentFrame) return;
if (currentFrame?.buttons?.length === 1) {
notification.error("At least one button is required");
return;
}
const newButtons = [...currentFrame.buttons];
newButtons.splice(activeButtonIndex, 1);
// @ts-ignore
setCurrentFrame({
...currentFrame,
// @ts-ignore
buttons: newButtons,
});
setActiveButtonIndex(0);
};
return (
<div className="mb-4 flex flex-col gap-2">
<div className="flex items-center gap-2">
<label htmlFor="buttons" className="block text-sm font-medium text-gray-700 ">
Buttons
</label>
{buttons.length < 4 && (
{/* @ts-ignore*/}
{currentFrame?.buttons?.length < 4 && (
<IconButton onClick={handleAddButton}>
<PlusIcon className="w-4 h-4 text-gray-700 border-2 border-black" />
</IconButton>
)}
</div>
<div className="flex flex-wrap gap-2">
{buttons.map((button, index) => (
{currentFrame?.buttons?.map((button, index) => (
<button key={index} className="btn btn-primary" onClick={() => handleButtonClick(index)}>
{button.label}
</button>
))}
</div>
{activeButtonIndex !== null && (
<ButtonEditor
button={buttons[activeButtonIndex]}
onSave={button => {
const newButtons = [...buttons];
newButtons[activeButtonIndex] = button;
setButtons(newButtons);
}}
onDelete={() => {
const newButtons = [...buttons];
if (newButtons.length === 1) {
notification.error("At least one button is required");
return;
}
newButtons.splice(activeButtonIndex, 1);
setButtons(newButtons);
setActiveButtonIndex(null);
}}
/>
{/* @ts-ignore */}
{currentFrame?.buttons[activeButtonIndex] && (
<ButtonEditor button={currentFrame.buttons[activeButtonIndex]} onSave={handleSave} onDelete={handleDelete} />
)}
<button onClick={handleSaveFrame} className="btn btn-secondary w-full mt-2 flex items-center justify-center">
Save Frame
Expand Down
44 changes: 25 additions & 19 deletions packages/nextjs/components/FrameEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import ButtonList from "./ButtonsList";
import InputField from "./InputField";
import { FrameImageMetadata } from "@coinbase/onchainkit";
import { MenuItem, Select } from "@mui/material";
import { useProductJourney } from "~~/providers/ProductProvider";

const FrameEditor = () => {
const { frame: dbFrame } = useProductJourney();
const frame = dbFrame?.frameJson;
const [imageUrl, setImageUrl] = useState<string>("");
const [additionalInput, setAdditionalInput] = useState<string>("");

const { currentFrame, setCurrentFrame } = useProductJourney();
const [imageUrlOption, setImageUrlOption] = useState("url");

useEffect(() => {
if (!frame) return;
setImageUrl((frame.image as FrameImageMetadata).src as string);
setAdditionalInput(frame.input?.text as string);
}, [frame]);

if (!currentFrame) return null;
return (
<div className="p-6 h-[100vh] bg-white rounded-md shadow-md flex flex-col gap-4">
<label htmlFor="imageInput" className="block text-sm font-medium text-gray-700">
Expand All @@ -29,7 +18,6 @@ const FrameEditor = () => {
value={imageUrlOption}
onChange={e => {
setImageUrlOption(e.target.value);
setImageUrl(""); // Clear the input box value when the dropdown selection changes
}}
variant="outlined"
>
Expand All @@ -39,15 +27,33 @@ const FrameEditor = () => {
<InputField
id="imageUrl"
label={imageUrlOption === "url" ? "Enter Image URL" : "Enter HTML Code"}
value={imageUrl}
onChange={setImageUrl}
// @ts-ignore
value={currentFrame?.image?.src || ""}
onChange={value => {
setCurrentFrame({
...currentFrame,
image: {
// @ts-ignore
...currentFrame?.image,
src: value,
},
});
}}
placeholder={imageUrlOption === "url" ? "Image URL" : "HTML Code"}
/>
<InputField
id="additionalInput"
label="Enter Additional Input"
value={additionalInput}
onChange={setAdditionalInput}
value={currentFrame?.input?.text || ""}
onChange={value => {
setCurrentFrame({
...currentFrame,
input: {
...currentFrame?.input,
text: value,
},
});
}}
placeholder="Additional Input"
/>
<ButtonList />
Expand Down
13 changes: 6 additions & 7 deletions packages/nextjs/components/FrameRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { useProductJourney } from "~~/providers/ProductProvider";

function FrameRender() {
const { frame: dbFrame } = useProductJourney();
const frame = dbFrame?.frameJson;
if (!frame) return null;
const { currentFrame } = useProductJourney();
if (!currentFrame) return null;
return (
<>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
// @ts-ignore
src={frame.image?.src as string}
src={currentFrame.image?.src as string}
alt="Description of the image"
style={{
borderRadius: "4px",
Expand All @@ -18,11 +17,11 @@ function FrameRender() {
height: "40vh", // Maintain aspect ratio
}}
/>
{frame.input?.text && (
{currentFrame.input?.text && (
<input
className="w-full p-2 border mt-1 border-gray-400 rounded bg-white" // Set background color to white
type="text"
placeholder={frame.input.text}
placeholder={currentFrame.input.text}
/>
)}
<div
Expand All @@ -33,7 +32,7 @@ function FrameRender() {
gap: "4px",
}}
>
{frame.buttons?.map(({ label, action }, index: number) => (
{currentFrame.buttons?.map(({ label, action }, index: number) => (
<button
type="button"
className={`bg-gray-200 p-1 hover:bg-gray-300 `}
Expand Down
26 changes: 18 additions & 8 deletions packages/nextjs/components/FramesSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import FrameRender from "./FrameRenderer";
import { FrameMetadataType } from "@coinbase/onchainkit";
import { useEffect, useMemo, useState } from "react";
import { useProductJourney } from "~~/providers/ProductProvider";
import { getFrameById } from "~~/services/frames";
import { Frame } from "~~/types/commontypes";

type FrameRenderProps = {
frames: FrameMetadataType[];
};

function FrameSidebar({ frames }: FrameRenderProps) {
function FrameSidebar() {
const { frames: dbFrames } = useProductJourney();
const [frames, setFrames] = useState<Frame[] | undefined>(undefined);
useEffect(() => {
if (dbFrames) {
Promise.all(dbFrames.map(frame => getFrameById(frame)))
.then(data => setFrames(data))
.catch(error => console.error("Error fetching frames:", error));
}
}, [dbFrames]);
if (!frames) return null;
return (
<div className="bg-white flex flex-col gap-2">
{frames.map((frame, index) => (
<div key={index} className="border-2 border-black">
<FrameRender frame={frame} />
<h3>{frame.name}</h3>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={frame.frameJson.image?.src} alt={frame.name} />
</div>
))}
</div>
Expand Down
Loading

0 comments on commit bb87c9e

Please sign in to comment.