iOS · SwiftUI · SDK 0.0.24
Feature Plans
Let app users explore your plans, vote on features, and follow your roadmap.
Complete the iOS quickstart first. These examples use the configured app and the MobileJoeUI package product.
Create a feature plan
- Select your app in the dashboard and open Feature Plans.
- Create a plan with a title and description. Keep its status Open for your first test.
- Choose Save. Feature plans have no separate publishing step; saved plans are available through the API.
Show the list
Add this screen to your app, or move its navigation link into your existing navigation stack:
import SwiftUI
import MobileJoeUI
struct FeedbackView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Feature Plans") {
FeaturePlansView(
configuration: .standard(recipient: "support@example.com"),
presentationMode: .inNavigationStack
)
}
}
.navigationTitle("Feedback")
}
}
}
FeaturePlansView loads data, fetches additional pages while scrolling, and supports pull to refresh. Tapping a plan opens its details. The vote button adds a vote; tapping it again removes that vote.
Search matches plan titles and descriptions. The toolbar menu offers newest-first or score sorting, individual status filters, and a roadmap containing Under review, Planned, and In progress. The default All filter includes those statuses plus Open; choose Completed to see completed plans. Closed plans are absent from these list filters.
Present a sheet
Use .asSheet to get the SDK's navigation stack and close button:
import SwiftUI
import MobileJoeUI
struct FeaturePlansButton: View {
@State private var showingPlans = false
var body: some View {
Button("Feature Plans") { showingPlans = true }
.sheet(isPresented: $showingPlans) {
FeaturePlansView(
configuration: .standard(recipient: "support@example.com"),
presentationMode: .asSheet
)
}
}
}
Suggestions and deep links
Replace support@example.com with your support address. The suggestion button opens the user's email app; it does not create a feature plan. Use .standard(recipient: "") to hide it. For custom localized email content, use FeaturePlansView.Configuration(recipient:subject:body:).
To open a specific plan, pass its integer ID as selectedFeaturePlanID: after presentationMode:. The view loads that plan and opens its details. Your app handles incoming URLs and extracts the ID. In the dashboard, open Feature Plans, click the settings gear, and save the Deep link base URL. The dashboard appends /ID when you copy a plan's deep link.
Use your own UI
Import MobileJoe and keep an observable FeaturePlans() model in @State. Use its all array for your list. Call try await featurePlans.load() for the next page, reload() to restart, vote(plan) to toggle a vote, or featurePlan(id:) to fetch one plan. Set sorting and filtering, or use search(for:) for debounced search. Use these APIs on the main actor after configuration and handle thrown errors.
Verify
Open your saved plan, vote twice, and confirm the score returns to its starting value. Change its dashboard status to Planned, refresh, and check the roadmap filter. If missing, check the selected filter and that the plan and SDK key belong to the same app.