From 4741898896b54c729fddcd77ad90d5fec2addfa5 Mon Sep 17 00:00:00 2001 From: Otaiki1 Date: Thu, 26 Feb 2026 13:56:16 +0100 Subject: [PATCH 1/4] draft --- soroban-client/package-lock.json | 12 +++++++++++ soroban-client/yarn.lock | 37 +++++++++++++++++++------------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/soroban-client/package-lock.json b/soroban-client/package-lock.json index 2de4c2f..3079019 100644 --- a/soroban-client/package-lock.json +++ b/soroban-client/package-lock.json @@ -69,6 +69,7 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -1585,6 +1586,7 @@ "integrity": "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1644,6 +1646,7 @@ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", @@ -2143,6 +2146,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2503,6 +2507,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3094,6 +3099,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3279,6 +3285,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -5480,6 +5487,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5489,6 +5497,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6177,6 +6186,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6339,6 +6349,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6614,6 +6625,7 @@ "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/soroban-client/yarn.lock b/soroban-client/yarn.lock index b68f446..b1562ad 100644 --- a/soroban-client/yarn.lock +++ b/soroban-client/yarn.lock @@ -264,10 +264,17 @@ resolved "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz" integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== -"@img/sharp-win32-x64@0.34.5": +"@img/sharp-darwin-arm64@0.34.5": version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz" - integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw== + resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== "@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": version "0.3.13" @@ -315,10 +322,10 @@ dependencies: fast-glob "3.3.1" -"@next/swc-win32-x64-msvc@16.1.4": +"@next/swc-darwin-arm64@16.1.4": version "16.1.4" - resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.4.tgz" - integrity sha512-JSVlm9MDhmTXw/sO2PE/MRj+G6XOSMZB+BcZ0a7d6KwVFZVpkHcb2okyoYFBaco6LeiL53BBklRlOrDDbOeE5w== + resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.4.tgz" + integrity sha512-T8atLKuvk13XQUdVLCv1ZzMPgLPW0+DWWbHSQXs0/3TjPrKNxTmUIhOEaoEyl3Z82k8h/gEtqyuoZGv6+Ugawg== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -379,10 +386,10 @@ source-map-js "^1.2.1" tailwindcss "4.1.18" -"@tailwindcss/oxide-win32-x64-msvc@4.1.18": +"@tailwindcss/oxide-darwin-arm64@4.1.18": version "4.1.18" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz" - integrity sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q== + resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz" + integrity sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A== "@tailwindcss/oxide@4.1.18": version "4.1.18" @@ -550,10 +557,10 @@ "@typescript-eslint/types" "8.53.1" eslint-visitor-keys "^4.2.1" -"@unrs/resolver-binding-win32-x64-msvc@1.11.1": +"@unrs/resolver-binding-darwin-arm64@1.11.1": version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz" - integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== acorn-jsx@^5.3.2: version "5.3.2" @@ -1894,10 +1901,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lightningcss-win32-x64-msvc@1.30.2: +lightningcss-darwin-arm64@1.30.2: version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz" - integrity sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw== + resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz" + integrity sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA== lightningcss@1.30.2: version "1.30.2" From 5b63380ff858b6e74445ec668b6c460b5ef58d14 Mon Sep 17 00:00:00 2001 From: Otaiki1 Date: Thu, 26 Feb 2026 14:06:20 +0100 Subject: [PATCH 2/4] wrap up changes --- soroban-client/README.md | 10 +- soroban-client/app/create-event/page.tsx | 221 +++++++++++++++ soroban-client/app/page.tsx | 2 +- soroban-client/components/Header.tsx | 16 +- soroban-client/lib/soroban.ts | 88 ++++++ soroban-client/package-lock.json | 340 +++++++++++++++++++++-- soroban-client/package.json | 1 + soroban-client/yarn.lock | 182 +++++++++++- 8 files changed, 826 insertions(+), 34 deletions(-) create mode 100644 soroban-client/app/create-event/page.tsx create mode 100644 soroban-client/lib/soroban.ts diff --git a/soroban-client/README.md b/soroban-client/README.md index e215bc4..0a6e34a 100644 --- a/soroban-client/README.md +++ b/soroban-client/README.md @@ -2,7 +2,15 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next- ## Getting Started -First, run the development server: +Before running the app, configure a few environment variables in `.env.local` (see example in the repo). At a minimum you should set: + +```env +NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org +NEXT_PUBLIC_NETWORK_PASSPHRASE="Test SDF Network ; September 2015" +NEXT_PUBLIC_EVENT_MANAGER_CONTRACT=C... # address of deployed EventManager contract +``` + +Once your env file is populated, start the development server: ```bash npm run dev diff --git a/soroban-client/app/create-event/page.tsx b/soroban-client/app/create-event/page.tsx new file mode 100644 index 0000000..29ec8ed --- /dev/null +++ b/soroban-client/app/create-event/page.tsx @@ -0,0 +1,221 @@ +"use client"; + +import React, { useState } from "react"; +import { useRouter } from "next/navigation"; +import { useWallet } from "@/contexts/WalletContext"; +import { createEvent } from "@/lib/soroban"; + +export default function CreateEventPage() { + const router = useRouter(); + const { address, isConnected, isInstalled, connect } = useWallet(); + + const [theme, setTheme] = useState(""); + const [description, setDescription] = useState(""); + const [startDate, setStartDate] = useState(""); + const [endDate, setEndDate] = useState(""); + const [price, setPrice] = useState(""); + const [tickets, setTickets] = useState(""); + const [image, setImage] = useState(null); + + const [errors, setErrors] = useState<{ [key: string]: string }>({}); + const [submitting, setSubmitting] = useState(false); + const [successMsg, setSuccessMsg] = useState(""); + const [errorMsg, setErrorMsg] = useState(""); + + const validate = () => { + const errs: { [key: string]: string } = {}; + const now = Date.now(); + + if (!theme.trim()) errs.theme = "Event name required"; + if (!startDate) errs.startDate = "Start date is required"; + if (!endDate) errs.endDate = "End date is required"; + if (startDate && new Date(startDate).getTime() <= now) + errs.startDate = "Start date must be in the future"; + if (startDate && endDate && new Date(endDate) <= new Date(startDate)) + errs.endDate = "End date must be after start date"; + if (!price) errs.price = "Price required"; + if (price && isNaN(Number(price))) errs.price = "Price must be a number"; + if (price && Number(price) < 0) errs.price = "Price cannot be negative"; + if (!tickets) errs.tickets = "Total tickets required"; + if (tickets && (!/^[0-9]+$/.test(tickets) || Number(tickets) <= 0)) + errs.tickets = "Must be a positive integer"; + + return errs; + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!address) { + if (isInstalled) { + await connect(); + } else { + alert("Please install Freighter to create an event."); + return; + } + } + const errs = validate(); + if (Object.keys(errs).length) { + setErrors(errs); + return; + } + setErrors({}); + setSubmitting(true); + setErrorMsg(""); + setSuccessMsg(""); + + try { + const organizer = address!; + const startUnix = Math.floor(new Date(startDate).getTime() / 1000); + const endUnix = Math.floor(new Date(endDate).getTime() / 1000); + const ticketPrice = BigInt(Math.floor(parseFloat(price) * 1_000_000)); + const totalTickets = BigInt(tickets); + + // for simplicity we use zero address as payment token; replace with real + // token contract address or allow user selection later. + const paymentToken = "0000000000000000000000000000000000000000000000000000000000000000"; + + const res = await createEvent({ + organizer, + theme, + eventType: description, + startTimeUnix: startUnix, + endTimeUnix: endUnix, + ticketPrice, + totalTickets, + paymentToken, + }); + + console.log("transaction result", res); + setSuccessMsg("Event created (tx " + res.hash + ")"); + // Optionally redirect to dashboard or home after creation + setTimeout(() => router.push("/"), 3000); + } catch (err: any) { + console.error(err); + setErrorMsg(err.message || "unknown error"); + } finally { + setSubmitting(false); + } + }; + + return ( +
+

Create Event

+ + {successMsg && ( +
{successMsg}
+ )} + {errorMsg && ( +
{errorMsg}
+ )} + +
+
+ + setTheme(e.target.value)} + className="mt-1 block w-full border-gray-300 rounded-md shadow-sm" + /> + {errors.theme && ( +

{errors.theme}

+ )} +
+ +
+ +