eventix.gno

3.39 Kb ยท 141 lines
  1package eventix
  2
  3import (
  4	"std"
  5	"strconv"
  6	"time"
  7
  8	"gno.land/p/demo/tokens/grc20"
  9	"gno.land/p/demo/tokens/grc721"
 10	"gno.land/p/nt/avl"
 11	"gno.land/p/nt/avl/pager"
 12	"gno.land/p/nt/ufmt"
 13)
 14
 15type Event struct {
 16	name         string
 17	description  string
 18	date         time.Time
 19	maxTickets   int
 20	price        uint64
 21	paymentToken any
 22	ticketsSold  int
 23}
 24
 25var (
 26	events              = avl.NewTree()
 27	eventCounter uint64 = 0
 28	tickets             = grc721.NewBasicNFT("Event Ticket", "EVTIX")
 29)
 30
 31func CreateEvent(_ realm, name, description, dateStr string, paymentToken any, maxTickets int, price uint64) uint64 {
 32	// validate inputs
 33	if maxTickets <= 0 {
 34		panic("Maximum tickets must be greater than 0")
 35	}
 36
 37	date, err := time.Parse("2006-01-02T15:04:05Z", dateStr)
 38	if err != nil {
 39		panic("Invalid date format. Use: YYYY-MM-DDThh:mm:ssZ")
 40	}
 41
 42	switch pt := paymentToken.(type) {
 43	case string:
 44		if pt != "ugnot" {
 45			panic("Unsupported native token")
 46		}
 47	case *grc20.Token:
 48		if pt == nil {
 49			panic("Invalid GRC20 token")
 50		}
 51	default:
 52		panic("Unsupported payment token type")
 53	}
 54
 55	newID := eventCounter + 1
 56	event := Event{
 57		name:         name,
 58		description:  description,
 59		date:         date,
 60		maxTickets:   maxTickets,
 61		price:        price,
 62		ticketsSold:  0,
 63		paymentToken: paymentToken,
 64	}
 65	events.Set(strconv.Itoa(int(newID)), event)
 66	eventCounter = newID
 67	std.Emit("EventCreated", "id", strconv.FormatUint(newID, 10), "name", name)
 68	return newID
 69}
 70
 71func BuyTicket(_ realm, eventId uint64) {
 72	event, exists := getEvent(eventId)
 73	if !exists {
 74		panic("Event does not exist")
 75	}
 76
 77	if event.ticketsSold >= event.maxTickets {
 78		panic("Event is sold out")
 79	}
 80
 81	buyer := std.PreviousRealm().Address()
 82
 83	switch pt := event.paymentToken.(type) {
 84	case string:
 85		if pt != "ugnot" {
 86			panic("Unsupported native token")
 87		}
 88		if std.OriginSend().AmountOf("ugnot") != int64(event.price) {
 89			panic(ufmt.Sprintf("Invalid payment amount: needs to be %dugnot", event.price))
 90		}
 91	case *grc20.Token:
 92		if err := pt.CallerTeller().Transfer(std.CurrentRealm().Address(), int64(event.price)); err != nil {
 93			panic("GRC20 transfer error: " + err.Error())
 94		}
 95	default:
 96		panic("Unsupported payment token type")
 97	}
 98
 99	// Mint NFT ticket
100	tokenId := grc721.TokenID(ufmt.Sprintf("event_%d_ticket_%d", eventId, event.ticketsSold+1))
101	tickets.Mint(buyer, tokenId)
102
103	event.ticketsSold++
104	events.Set(strconv.Itoa(int(eventId)), event)
105}
106
107func Render(path string) string {
108	output := "# Event Ticketing System\n\n"
109
110	pg := pager.NewPager(events, 10, true).MustGetPageByPath(path)
111
112	for _, item := range pg.Items {
113		id, _ := strconv.ParseUint(item.Key, 10, 64)
114		event := item.Value.(Event)
115
116		output += ufmt.Sprintf("## Event #%d: %s\n", id, event.name)
117		output += ufmt.Sprintf("Description: %s\n", event.description)
118		output += ufmt.Sprintf("Date: %s\n", event.date.Format(time.RFC3339))
119		output += ufmt.Sprintf("Tickets: %d/%d\n", event.ticketsSold, event.maxTickets)
120		output += ufmt.Sprintf("Price: %d %v\n\n", event.price, event.paymentToken)
121
122		if event.ticketsSold < event.maxTickets {
123			output += ufmt.Sprintf("[Buy Ticket](/r/jjoptimist/eventix/BuyTicket?eventId=%d)\n", id)
124		} else {
125			output += "**SOLD OUT**\n"
126		}
127		output += "---\n\n"
128	}
129
130	output += pg.Picker(path)
131
132	return output
133}
134
135func getEvent(eventId uint64) (Event, bool) {
136	value, exists := events.Get(strconv.Itoa(int(eventId)))
137	if !exists {
138		return Event{}, false
139	}
140	return value.(Event), true
141}