Skip to main content

Prerequisites

1. Show feature requests

let requests = try await grantiva.feedback.getFeatureRequests(sort: "votes")

for request in requests {
    print("\(request.title)\(request.voteCount) votes (\(request.status))")
}

2. Let users submit ideas

let newRequest = try await grantiva.feedback.submitFeatureRequest(
    title: "Dark Mode Support",
    description: "Please add a dark mode option to reduce eye strain."
)

3. Add voting

// Vote
try await grantiva.feedback.vote(for: feature.id)

// Unvote
try await grantiva.feedback.removeVote(for: feature.id)
Each user/device gets one vote per feature. feature.hasVoted tells you if the current user already voted.

4. Add comments

let comments = try await grantiva.feedback.getComments(for: feature.id)

try await grantiva.feedback.addComment(to: feature.id, body: "Love this idea!")

5. Support tickets

// Submit a ticket
let ticket = try await grantiva.feedback.submitTicket(
    subject: "App crashes on launch",
    body: "After updating to v2.1, the app crashes on my iPhone 15...",
    email: "user@example.com"
)

// List user's tickets
let tickets = try await grantiva.feedback.getUsersTickets()

// View conversation
let (ticket, messages) = try await grantiva.feedback.getTicket(id: ticketId)

// Reply
try await grantiva.feedback.reply(to: ticketId, body: "Here's the crash log...")

6. With user identity (optional)

If you identify users, feedback persists across devices:
await grantiva.identify("user_123")

// Now all feedback calls are scoped to this user
let tickets = try await grantiva.feedback.getUsersTickets()

SwiftUI example

struct FeatureListView: View {
    @State private var features: [FeatureRequest] = []
    let grantiva: Grantiva

    var body: some View {
        List(features) { feature in
            HStack {
                VStack(alignment: .leading) {
                    Text(feature.title).font(.headline)
                    Text(feature.status.rawValue)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                Spacer()
                Button {
                    Task {
                        if feature.hasVoted {
                            try await grantiva.feedback.removeVote(for: feature.id)
                        } else {
                            try await grantiva.feedback.vote(for: feature.id)
                        }
                        await loadFeatures()
                    }
                } label: {
                    Label("\(feature.voteCount)", systemImage: feature.hasVoted ? "hand.thumbsup.fill" : "hand.thumbsup")
                }
                .buttonStyle(.bordered)
            }
        }
        .task { await loadFeatures() }
    }

    func loadFeatures() async {
        features = (try? await grantiva.feedback.getFeatureRequests()) ?? []
    }
}

Next steps