flutter_jira_issue_collector 0.2.0 copy "flutter_jira_issue_collector: ^0.2.0" to clipboard
flutter_jira_issue_collector: ^0.2.0 copied to clipboard

Jira Issue Collector for Flutter. Fetch collector fields dynamically, show customizable forms, or submit issues programmatically in the background.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_jira_issue_collector/flutter_jira_issue_collector.dart';

import 'generated/nmbma_collector.dart';

void main() {
  runApp(const ExampleApp());
}

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Jira Issue Collector Example',
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Using the generated collector — no manual config needed.
  late final JiraIssueCollector _collector;

  @override
  void initState() {
    super.initState();
    _collector = NmbmaCollector.createCollector();
  }

  @override
  void dispose() {
    _collector.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Jira Collector Example')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // --- UI Mode: Full-screen dialog ---
          _SectionCard(
            title: 'UI Mode — Full-screen Dialog',
            description:
                'Opens the issue collector form as a full-screen dialog. '
                'Fields are fetched dynamically from Jira.',
            buttonLabel: 'Open Dialog',
            onPressed: () => _showDialog(context),
          ),
          const SizedBox(height: 16),

          // --- UI Mode: Bottom sheet ---
          _SectionCard(
            title: 'UI Mode — Bottom Sheet',
            description:
                'Opens the issue collector as a draggable bottom sheet.',
            buttonLabel: 'Open Bottom Sheet',
            onPressed: () => _showBottomSheet(context),
          ),
          const SizedBox(height: 16),

          // --- UI Mode: With prefill + hidden fields ---
          _SectionCard(
            title: 'UI Mode — Prefilled + Hidden Fields',
            description:
                'Opens the form with name and email prefilled and hidden, '
                'so the user does not see or modify them.',
            buttonLabel: 'Open Prefilled',
            onPressed: () => _showPrefilled(context),
          ),
          const SizedBox(height: 16),

          // --- Background Mode: type-safe ---
          _SectionCard(
            title: 'Background Mode — Type-safe Submit',
            description: 'Submits an issue silently using the generated '
                'NmbmaCollector.build() — field names are checked '
                'at compile time.',
            buttonLabel: 'Submit in Background',
            onPressed: () => _submitBackground(context),
          ),
          const SizedBox(height: 16),

          // --- Automated Error Reporting ---
          _SectionCard(
            title: 'Automated Error Reporting',
            description:
                'Simulates an HTTP 500 error and creates a Jira ticket '
                'with full request/response details using the generated '
                'typed fields.',
            buttonLabel: 'Simulate Server Error',
            onPressed: () => _simulateErrorReport(context),
          ),
          const SizedBox(height: 16),

          // --- Inspect Fields ---
          _SectionCard(
            title: 'Inspect Available Fields',
            description:
                'Fetches and displays the fields available in the collector. '
                'Useful for verifying generated code is up-to-date.',
            buttonLabel: 'Fetch Fields',
            onPressed: () => _inspectFields(context),
          ),
        ],
      ),
    );
  }

  Future<void> _showDialog(BuildContext context) async {
    final result = await _collector.showCollector(
      context,
      onResult: (r) => _showSnackBar(context, r),
    );
    if (result != null && context.mounted) {
      _showSnackBar(context, result);
    }
  }

  Future<void> _showBottomSheet(BuildContext context) async {
    final result = await _collector.showCollectorBottomSheet(
      context,
      onResult: (r) => _showSnackBar(context, r),
    );
    if (result != null && context.mounted) {
      _showSnackBar(context, result);
    }
  }

  Future<void> _showPrefilled(BuildContext context) async {
    // Use generated constants for field IDs — no magic strings.
    final result = await _collector.showCollector(
      context,
      prefillValues: {
        NmbmaCollector.name: 'John Doe',
        NmbmaCollector.email: 'user@example.com',
      },
      hiddenFieldIds: {NmbmaCollector.name, NmbmaCollector.email},
      onResult: (r) => _showSnackBar(context, r),
    );
    if (result != null && context.mounted) {
      _showSnackBar(context, result);
    }
  }

  Future<void> _submitBackground(BuildContext context) async {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Submitting issue...')),
    );

    // Type-safe submission — the compiler ensures we only use fields
    // that actually exist in the collector.
    final result = await _collector.submitInBackground(
      fieldValues: NmbmaCollector.build(
        whatWentWrong:
            'This issue was submitted programmatically from the Flutter app.\n'
            'Timestamp: ${DateTime.now().toUtc().toIso8601String()}',
        name: 'Flutter App',
        email: 'flutter-app@example.com',
      ),
    );

    if (!context.mounted) return;
    _showSnackBar(context, result);
  }

  Future<void> _simulateErrorReport(BuildContext context) async {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Reporting simulated error...')),
    );

    // Build a rich error description — the kind an interceptor would send.
    final report = StringBuffer()
      ..writeln('[Mobile] Server 500 — POST /api/example/action')
      ..writeln()
      ..writeln('Method: POST')
      ..writeln('Path: /api/example/action')
      ..writeln('Status: 500')
      ..writeln('Timestamp: ${DateTime.now().toUtc().toIso8601String()}')
      ..writeln()
      ..writeln('--- Request Body ---')
      ..writeln('{"id": "abc-123", "action": "submit"}')
      ..writeln()
      ..writeln('--- Response Body ---')
      ..writeln('{"error": "Internal Server Error"}')
      ..writeln()
      ..writeln('--- User ---')
      ..writeln('ID: user-42')
      ..writeln('Name: Jane Doe')
      ..writeln('Email: jane@example.com');

    // Submit using the generated typed helper.
    final result = await _collector.submitInBackground(
      fieldValues: NmbmaCollector.build(
        whatWentWrong: report.toString(),
        name: 'Jane Doe',
        email: 'jane@example.com',
      ),
    );

    if (!context.mounted) return;
    _showSnackBar(context, result);
  }

  Future<void> _inspectFields(BuildContext context) async {
    try {
      final fields = await _collector.fetchFields();
      if (!context.mounted) return;

      showDialog(
        context: context,
        builder: (ctx) => AlertDialog(
          title: const Text('Available Fields'),
          content: SizedBox(
            width: double.maxFinite,
            child: ListView.builder(
              shrinkWrap: true,
              itemCount: fields.length,
              itemBuilder: (ctx, i) {
                final f = fields[i];
                return ListTile(
                  title: Text(f.label),
                  subtitle: Text(
                    'id: ${f.id} | type: ${f.type.name} | '
                    'required: ${f.required}',
                  ),
                  dense: true,
                );
              },
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(ctx).pop(),
              child: const Text('Close'),
            ),
          ],
        ),
      );
    } catch (e) {
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error fetching fields: $e')),
      );
    }
  }

  void _showSnackBar(BuildContext context, SubmissionResult result) {
    if (!context.mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(
          result.success
              ? 'Issue submitted! ${result.issueKey ?? ''}'
              : 'Failed: ${result.errorMessage}',
        ),
        backgroundColor: result.success ? Colors.green : Colors.red,
      ),
    );
  }
}

class _SectionCard extends StatelessWidget {
  final String title;
  final String description;
  final String buttonLabel;
  final VoidCallback onPressed;

  const _SectionCard({
    required this.title,
    required this.description,
    required this.buttonLabel,
    required this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(title, style: Theme.of(context).textTheme.titleMedium),
            const SizedBox(height: 8),
            Text(description),
            const SizedBox(height: 12),
            ElevatedButton(
              onPressed: onPressed,
              child: Text(buttonLabel),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
160
points
32
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Jira Issue Collector for Flutter. Fetch collector fields dynamically, show customizable forms, or submit issues programmatically in the background.

Homepage
Repository (GitHub)
View/report issues

Topics

#jira #issue-collector #issue-tracking #feedback

License

MIT (license)

Dependencies

dio, flutter, html

More

Packages that depend on flutter_jira_issue_collector