Pārlūkot izejas kodu

Fix empty-URL crash in CachedNetworkImage across 5 components + sync latest FlutterFlow state

Wrapped the Image widget in a ConditionalBuilder (guard on the same
logo-URL expression) in HorecagelegenheidoverzichtKaart, kaartTabelUitgaanComp,
kaartTabelUitgaanSComp, HomeUitgaantabelKaartComponent, and
PUitgaantabelKaartComponent — an empty imageUrl was throwing an uncaught
ArgumentError at widget-construction time, before CachedNetworkImage's own
error handling ever got a chance to run. Shows a broken-image icon instead
of crashing when the API returns no logo.

Also pulls in Bob's concurrent FlutterFlow builder work (login flow,
new kanweg page, API call additions) and adds a "research first" procedure
note to CLAUDE.md.
bob 1 mēnesi atpakaļ
vecāks
revīzija
f7eedd55f0

+ 12 - 0
CLAUDE.md

@@ -88,3 +88,15 @@ Voeg dus na elke pull, vóór je staged, deze regel weer toe aan
 # Claude Code session state (not app code)
 .claude/
 ```
+
+## Eerst research, dan bouwen (sinds 2026-08-03)
+
+Voordat je aan een niet-triviale taak begint (een bug fix, een nieuw
+patroon, een integratie): zoek eerst kort op internet naar bestaande
+oplossingen/patronen (bijv. "FlutterFlow ConditionalBuilder default
+image", "Drupal 7 Services session auth FlutterFlow") voordat je het
+zelf helemaal uitvindt via trial-and-error in de builder. Dit kan
+sneller zijn dan zelf experimenteren, vooral bij FlutterFlow-builder-
+specifieke UI-flows of Drupal-integratiepatronen. Geldt niet voor
+triviale/mechanische herhaling van een patroon dat al binnen deze
+sessie is uitgezocht en bevestigd werkt.

+ 4 - 4
ios/Runner.xcodeproj/project.pbxproj

@@ -44,8 +44,8 @@
 		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		6436409D27A31CD000820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		6436409427A31CD400820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409127A31CD600820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409727A31CD700820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -225,8 +225,8 @@
 		6436409C27A31CD800820AF7 /* InfoPlist.strings */ = {
 			isa = PBXVariantGroup;
 			children = (
-				6436409D27A31CD000820AF7 /* nl */,
-				6436409427A31CD400820AF7 /* en */,
+				6436409127A31CD600820AF7 /* nl */,
+				6436409727A31CD700820AF7 /* en */,
 			);
 			name = InfoPlist.strings;
 			sourceTree = "<group>";

+ 66 - 1
lib/backend/api_requests/api_calls.dart

@@ -145,12 +145,76 @@ class ZZUserEstablishmentsTESTCall {
 }
 
 class FavorietenAgendaCall {
-  static Future<ApiCallResponse> call() async {
+  static Future<ApiCallResponse> call({
+    String? sessionName = '',
+    String? sessionId = '',
+  }) async {
     return ApiManager.instance.makeApiCall(
       callName: 'FavorietenAgenda',
       apiUrl:
           'https://uitgaanskrant.com/nl/flutterdrup/views/flutterfavorietenagenda.json?display_id=services_1',
       callType: ApiCallType.GET,
+      headers: {
+        'Cookie': '{{session_name}}={{sessid}}',
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+        'X-Requested-With': 'XMLHttpRequest',
+      },
+      params: {
+        'session_name': sessionName,
+        'sessionid': sessionId,
+      },
+      returnBody: true,
+      encodeBodyUtf8: false,
+      decodeUtf8: false,
+      cache: false,
+      isStreamingApi: false,
+      alwaysAllowBody: false,
+    );
+  }
+
+  static String? sessionid(dynamic response) => castToType<String>(getJsonField(
+        response,
+        r'''$.sessid''',
+      ));
+  static String? sessionname(dynamic response) =>
+      castToType<String>(getJsonField(
+        response,
+        r'''$.session_name''',
+      ));
+  static String? token(dynamic response) => castToType<String>(getJsonField(
+        response,
+        r'''$.token''',
+      ));
+  static String? drupaluserid(dynamic response) =>
+      castToType<String>(getJsonField(
+        response,
+        r'''$.user.uid''',
+      ));
+  static String? establishmentTitle(dynamic response) =>
+      castToType<String>(getJsonField(
+        response,
+        r'''$[:].node_title''',
+      ));
+  static String? establishmentLogo(dynamic response) =>
+      castToType<String>(getJsonField(
+        response,
+        r'''$[:].logohoreca''',
+      ));
+  static String? establishmentNid(dynamic response) =>
+      castToType<String>(getJsonField(
+        response,
+        r'''$[:].nid''',
+      ));
+}
+
+class FavorietenAgendaTESTKANWEGCall {
+  static Future<ApiCallResponse> call() async {
+    return ApiManager.instance.makeApiCall(
+      callName: 'FavorietenAgendaTESTKANWEG',
+      apiUrl:
+          'https://uitgaanskrant.com/nl/cookie-testcda.php?display_id=services_1',
+      callType: ApiCallType.GET,
       headers: {
         'Cookie':
             'SSESSfb38a72b665678c06dea69b92d0e88c6=NPHBx1J_vK03xg3ysN3SjaPj3iWjefsIBXxxTWipEtI',
@@ -166,6 +230,7 @@ class FavorietenAgendaCall {
       cache: false,
       isStreamingApi: true,
       alwaysAllowBody: false,
+      client: ApiManager.getClient(withCredentials: true),
     );
   }
 

+ 19 - 7
lib/components/kaart_tabel_uitgaan_comp_widget.dart

@@ -130,13 +130,25 @@ class _KaartTabelUitgaanCompWidgetState
                   children: [
                     Align(
                       alignment: AlignmentDirectional(1.0, 0.0),
-                      child: ClipRRect(
-                        borderRadius: BorderRadius.circular(8.0),
-                        child: Image.network(
-                          widget!.logo!,
-                          height: 220.0,
-                          fit: BoxFit.fitHeight,
-                        ),
+                      child: Builder(
+                        builder: (context) {
+                          if (widget!.logo != '') {
+                            return ClipRRect(
+                              borderRadius: BorderRadius.circular(8.0),
+                              child: Image.network(
+                                widget!.logo!,
+                                height: 220.0,
+                                fit: BoxFit.fitHeight,
+                              ),
+                            );
+                          } else {
+                            return Icon(
+                              Icons.image_not_supported,
+                              color: FlutterFlowTheme.of(context).primaryText,
+                              size: 24.0,
+                            );
+                          }
+                        },
                       ),
                     ),
                     Align(

+ 20 - 7
lib/components/kaart_tabel_uitgaan_s_comp_widget.dart

@@ -157,13 +157,26 @@ class _KaartTabelUitgaanSCompWidgetState
                       children: [
                         Align(
                           alignment: AlignmentDirectional(1.0, 0.0),
-                          child: ClipRRect(
-                            borderRadius: BorderRadius.only(),
-                            child: Image.network(
-                              widget!.logo!,
-                              height: 220.0,
-                              fit: BoxFit.fitHeight,
-                            ),
+                          child: Builder(
+                            builder: (context) {
+                              if (widget!.logo != '') {
+                                return ClipRRect(
+                                  borderRadius: BorderRadius.only(),
+                                  child: Image.network(
+                                    widget!.logo!,
+                                    height: 220.0,
+                                    fit: BoxFit.fitHeight,
+                                  ),
+                                );
+                              } else {
+                                return Icon(
+                                  Icons.image_not_supported,
+                                  color:
+                                      FlutterFlowTheme.of(context).primaryText,
+                                  size: 24.0,
+                                );
+                              }
+                            },
                           ),
                         ),
                         Align(

+ 12 - 1
lib/flutter_flow/internationalization.dart

@@ -156,7 +156,7 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
     },
     'gkx4luhw': {
       'nl': 'Inloggen',
-      'en': 'horecagelegenheden',
+      'en': 'Inloggen',
     },
     'utppw2si': {
       'nl': 'Wachtwoord vergeten?',
@@ -178,6 +178,10 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'puitgaan',
       'en': 'puitgaan',
     },
+    'ym0dczsr': {
+      'nl': 'kanwegtest',
+      'en': 'kanwegtest',
+    },
     'bokhk9vk': {
       'nl': 'Home',
       'en': '',
@@ -438,6 +442,13 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'en': '',
     },
   },
+  // kanweg
+  {
+    '3f7lzegf': {
+      'nl': 'Home',
+      'en': '',
+    },
+  },
   // PUitgaantabelKaartComponent
   {
     '4lehigdg': {

+ 8 - 1
lib/flutter_flow/nav/nav.dart

@@ -50,7 +50,9 @@ const debugRouteLinkMap = {
   '/wachtwoordVergeten':
       'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=wachtwoordVergeten',
   '/favorieten':
-      'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorieten'
+      'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorieten',
+  '/kanweg':
+      'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg'
 };
 
 class AppStateNotifier extends ChangeNotifier {
@@ -226,6 +228,11 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter(
           name: FavorietenWidget.routeName,
           path: FavorietenWidget.routePath,
           builder: (context, params) => FavorietenWidget(),
+        ),
+        FFRoute(
+          name: KanwegWidget.routeName,
+          path: KanwegWidget.routePath,
+          builder: (context, params) => KanwegWidget(),
         )
       ].map((r) => r.toRoute(appStateNotifier)).toList(),
       observers: [routeObserver],

+ 20 - 8
lib/horecagelegenhedenoverzicht/horecagelegenheidoverzicht_kaart/horecagelegenheidoverzicht_kaart_widget.dart

@@ -158,14 +158,26 @@ class _HorecagelegenheidoverzichtKaartWidgetState
                   child: Stack(
                     alignment: AlignmentDirectional(-1.0, 1.0),
                     children: [
-                      ClipRRect(
-                        borderRadius: BorderRadius.circular(8.0),
-                        child: CachedNetworkImage(
-                          fadeInDuration: Duration(milliseconds: 0),
-                          fadeOutDuration: Duration(milliseconds: 0),
-                          imageUrl: widget!.logo!,
-                          fit: BoxFit.cover,
-                        ),
+                      Builder(
+                        builder: (context) {
+                          if (widget!.logo != '') {
+                            return ClipRRect(
+                              borderRadius: BorderRadius.circular(8.0),
+                              child: CachedNetworkImage(
+                                fadeInDuration: Duration(milliseconds: 0),
+                                fadeOutDuration: Duration(milliseconds: 0),
+                                imageUrl: widget!.logo!,
+                                fit: BoxFit.cover,
+                              ),
+                            );
+                          } else {
+                            return Icon(
+                              Icons.image_not_supported,
+                              color: FlutterFlowTheme.of(context).primaryText,
+                              size: 24.0,
+                            );
+                          }
+                        },
                       ),
                       Align(
                         alignment: AlignmentDirectional(-1.0, 1.0),

+ 1 - 0
lib/index.dart

@@ -19,3 +19,4 @@ export '/horecagelegenhedenoverzicht/horecagelegenheden_overzicht_sort_page/hore
 export '/wachtwoord_vergeten/wachtwoord_vergeten_widget.dart'
     show WachtwoordVergetenWidget;
 export '/favorieten/favorieten_widget.dart' show FavorietenWidget;
+export '/kanweg/kanweg/kanweg_widget.dart' show KanwegWidget;

+ 41 - 0
lib/kanweg/kanweg/kanweg_model.dart

@@ -0,0 +1,41 @@
+import '/backend/api_requests/api_calls.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import '/flutter_flow/flutter_flow_widgets.dart';
+import 'dart:ui';
+import 'kanweg_widget.dart' show KanwegWidget;
+import 'package:flutter/material.dart';
+import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:provider/provider.dart';
+
+class KanwegModel extends FlutterFlowModel<KanwegWidget> {
+  final Map<String, DebugDataField> debugGeneratorVariables = {};
+  final Map<String, DebugDataField> debugBackendQueries = {};
+  final Map<String, FlutterFlowModel> widgetBuilderComponents = {};
+  @override
+  void initState(BuildContext context) {
+    debugLogWidgetClass(this);
+  }
+
+  @override
+  void dispose() {}
+
+  @override
+  WidgetClassDebugData toWidgetClassDebugData() => WidgetClassDebugData(
+        generatorVariables: debugGeneratorVariables.entries,
+        backendQueries: debugBackendQueries.entries,
+        componentStates: {
+          ...widgetBuilderComponents.map(
+            (key, value) => MapEntry(
+              key,
+              value.toWidgetClassDebugData(),
+            ),
+          ),
+        }.withoutNulls.entries,
+        link:
+            'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd/tab=uiBuilder&page=kanweg',
+        searchReference: 'reference=OgZrYW53ZWdQAVoGa2Fud2Vn',
+        widgetClassName: 'kanweg',
+      );
+}

+ 186 - 0
lib/kanweg/kanweg/kanweg_widget.dart

@@ -0,0 +1,186 @@
+import '/backend/api_requests/api_calls.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import '/flutter_flow/flutter_flow_widgets.dart';
+import 'dart:ui';
+import 'package:flutter/material.dart';
+import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:provider/provider.dart';
+import 'kanweg_model.dart';
+export 'kanweg_model.dart';
+
+class KanwegWidget extends StatefulWidget {
+  const KanwegWidget({super.key});
+
+  static String routeName = 'kanweg';
+  static String routePath = '/kanweg';
+
+  @override
+  State<KanwegWidget> createState() => _KanwegWidgetState();
+}
+
+class _KanwegWidgetState extends State<KanwegWidget> with RouteAware {
+  late KanwegModel _model;
+
+  final scaffoldKey = GlobalKey<ScaffoldState>();
+
+  @override
+  void initState() {
+    super.initState();
+    _model = createModel(context, () => KanwegModel());
+  }
+
+  @override
+  void dispose() {
+    routeObserver.unsubscribe(this);
+
+    _model.dispose();
+
+    super.dispose();
+  }
+
+  @override
+  void didUpdateWidget(KanwegWidget oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    _model.widget = widget;
+  }
+
+  @override
+  void didChangeDependencies() {
+    super.didChangeDependencies();
+    final route = DebugModalRoute.of(context);
+    if (route != null) {
+      routeObserver.subscribe(this, route);
+    }
+    debugLogGlobalProperty(context);
+  }
+
+  @override
+  void didPopNext() {
+    if (mounted && DebugFlutterFlowModelContext.maybeOf(context) == null) {
+      setState(() => _model.isRouteVisible = true);
+      debugLogWidgetClass(_model);
+    }
+  }
+
+  @override
+  void didPush() {
+    if (mounted && DebugFlutterFlowModelContext.maybeOf(context) == null) {
+      setState(() => _model.isRouteVisible = true);
+      debugLogWidgetClass(_model);
+    }
+  }
+
+  @override
+  void didPop() {
+    _model.isRouteVisible = false;
+  }
+
+  @override
+  void didPushNext() {
+    _model.isRouteVisible = false;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    DebugFlutterFlowModelContext.maybeOf(context)
+        ?.parentModelCallback
+        ?.call(_model);
+    context.watch<FFAppState>();
+
+    return GestureDetector(
+      onTap: () {
+        FocusScope.of(context).unfocus();
+        FocusManager.instance.primaryFocus?.unfocus();
+      },
+      child: Scaffold(
+        key: scaffoldKey,
+        backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
+        body: SafeArea(
+          top: true,
+          child: FutureBuilder<ApiCallResponse>(
+            future: FavorietenAgendaCall.call(
+              sessionName: FFAppState().userSessionname,
+              sessionId: FFAppState().userSessionid,
+            ),
+            builder: (context, snapshot) {
+              // Customize what your widget looks like when it's loading.
+              if (!snapshot.hasData) {
+                return Center(
+                  child: SizedBox(
+                    width: 80.0,
+                    height: 80.0,
+                    child: SpinKitFadingCircle(
+                      color: Color(0xFFB1061E),
+                      size: 80.0,
+                    ),
+                  ),
+                );
+              }
+              final columnFavorietenAgendaResponse = snapshot.data!;
+              _model.debugBackendQueries[
+                      'FavorietenAgendaCall_statusCode_Column_26my15h6'] =
+                  debugSerializeParam(
+                columnFavorietenAgendaResponse.statusCode,
+                ParamType.int,
+                link:
+                    'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg',
+                name: 'int',
+                nullable: false,
+              );
+              _model.debugBackendQueries[
+                      'FavorietenAgendaCall_responseBody_Column_26my15h6'] =
+                  debugSerializeParam(
+                columnFavorietenAgendaResponse.bodyText,
+                ParamType.String,
+                link:
+                    'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg',
+                name: 'String',
+                nullable: false,
+              );
+              debugLogWidgetClass(_model);
+
+              return Builder(
+                builder: (context) {
+                  final items = getJsonField(
+                    columnFavorietenAgendaResponse.jsonBody,
+                    r'''$''',
+                  ).toList();
+                  _model.debugGeneratorVariables[
+                          'items${items.length > 100 ? ' (first 100)' : ''}'] =
+                      debugSerializeParam(
+                    items.take(100),
+                    ParamType.JSON,
+                    isList: true,
+                    link:
+                        'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg',
+                    name: 'dynamic',
+                    nullable: false,
+                  );
+                  debugLogWidgetClass(_model);
+
+                  return Column(
+                    mainAxisSize: MainAxisSize.max,
+                    children: List.generate(items.length, (itemsIndex) {
+                      final itemsItem = items[itemsIndex];
+                      return ClipRRect(
+                        borderRadius: BorderRadius.circular(8.0),
+                        child: Image.network(
+                          'https://picsum.photos/seed/736/600',
+                          width: 200.0,
+                          height: 200.0,
+                          fit: BoxFit.cover,
+                        ),
+                      );
+                    }),
+                  );
+                },
+              );
+            },
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 0 - 1
lib/login/login/login_model.dart

@@ -1,4 +1,3 @@
-import '/auth/custom_auth/auth_util.dart';
 import '/backend/api_requests/api_calls.dart';
 import '/backend/api_requests/api_streaming.dart';
 import '/components/header_buttons_component_widget.dart';

+ 66 - 21
lib/login/login/login_widget.dart

@@ -1,4 +1,3 @@
-import '/auth/custom_auth/auth_util.dart';
 import '/backend/api_requests/api_calls.dart';
 import '/backend/api_requests/api_streaming.dart';
 import '/components/header_buttons_component_widget.dart';
@@ -437,7 +436,6 @@ class _LoginWidgetState extends State<LoginWidget> with RouteAware {
                           ),
                           FFButtonWidget(
                             onPressed: () async {
-                              Function() _navigate = () {};
                               _model.apiResultlco = await LoginCall.call(
                                 username:
                                     _model.usernameFieldTextController.text,
@@ -446,24 +444,27 @@ class _LoginWidgetState extends State<LoginWidget> with RouteAware {
                               );
 
                               if ((_model.apiResultlco?.succeeded ?? true)) {
-                                GoRouter.of(context).prepareAuthEvent();
-                                await authManager.signIn(
-                                  authenticationToken: getJsonField(
-                                    (_model.apiResultlco?.jsonBody ?? ''),
-                                    r'''$.sessid''',
-                                  ).toString(),
-                                  refreshToken: getJsonField(
-                                    (_model.apiResultlco?.jsonBody ?? ''),
-                                    r'''$.session_name''',
-                                  ).toString(),
-                                  authUid: getJsonField(
-                                    (_model.apiResultlco?.jsonBody ?? ''),
-                                    r'''$.user.uid''',
-                                  ).toString(),
+                                FFAppState().userSessionid = getJsonField(
+                                  (_model.apiResultlco?.jsonBody ?? ''),
+                                  r'''$.sessid''',
+                                ).toString();
+                                FFAppState().userSessionname = getJsonField(
+                                  (_model.apiResultlco?.jsonBody ?? ''),
+                                  r'''$.session_name''',
+                                ).toString();
+                                FFAppState().userCsrftoken = getJsonField(
+                                  (_model.apiResultlco?.jsonBody ?? ''),
+                                  r'''$.token''',
+                                ).toString();
+                                FFAppState().userName = getJsonField(
+                                  (_model.apiResultlco?.jsonBody ?? ''),
+                                  r'''$.user.name''',
+                                ).toString();
+                                FFAppState().userUid = getJsonField(
+                                  (_model.apiResultlco?.jsonBody ?? ''),
+                                  r'''$.user.uid''',
                                 );
-                                _navigate = () => context.goNamedAuth(
-                                    SelectprovinciegemeenteWidget.routeName,
-                                    context.mounted);
+                                safeSetState(() {});
                               } else {
                                 ScaffoldMessenger.of(context).showSnackBar(
                                   SnackBar(
@@ -481,8 +482,6 @@ class _LoginWidgetState extends State<LoginWidget> with RouteAware {
                                 );
                               }
 
-                              _navigate();
-
                               safeSetState(() {});
                             },
                             text: FFLocalizations.of(context).getText(
@@ -731,6 +730,52 @@ class _LoginWidgetState extends State<LoginWidget> with RouteAware {
                               borderRadius: BorderRadius.circular(8.0),
                             ),
                           ),
+                          FFButtonWidget(
+                            onPressed: () async {
+                              context.pushNamed(
+                                HorecagelegenhedenOverzichtWidget.routeName,
+                                queryParameters: {
+                                  'plaats': serializeParam(
+                                    FFAppState().provincieSelectId,
+                                    ParamType.String,
+                                  ),
+                                }.withoutNulls,
+                              );
+                            },
+                            text: FFLocalizations.of(context).getText(
+                              'ym0dczsr' /* kanwegtest */,
+                            ),
+                            options: FFButtonOptions(
+                              height: 40.0,
+                              padding: EdgeInsetsDirectional.fromSTEB(
+                                  16.0, 0.0, 16.0, 0.0),
+                              iconPadding: EdgeInsetsDirectional.fromSTEB(
+                                  0.0, 0.0, 0.0, 0.0),
+                              color: FlutterFlowTheme.of(context).primary,
+                              textStyle: FlutterFlowTheme.of(context)
+                                  .titleSmall
+                                  .override(
+                                    font: GoogleFonts.interTight(
+                                      fontWeight: FlutterFlowTheme.of(context)
+                                          .titleSmall
+                                          .fontWeight,
+                                      fontStyle: FlutterFlowTheme.of(context)
+                                          .titleSmall
+                                          .fontStyle,
+                                    ),
+                                    color: Colors.white,
+                                    letterSpacing: 0.0,
+                                    fontWeight: FlutterFlowTheme.of(context)
+                                        .titleSmall
+                                        .fontWeight,
+                                    fontStyle: FlutterFlowTheme.of(context)
+                                        .titleSmall
+                                        .fontStyle,
+                                  ),
+                              elevation: 0.0,
+                              borderRadius: BorderRadius.circular(8.0),
+                            ),
+                          ),
                         ],
                       ),
                     ],

+ 31 - 12
lib/uitgaanspaginas/home_uitgaantabel_kaart_component/home_uitgaantabel_kaart_component_widget.dart

@@ -212,18 +212,37 @@ class _HomeUitgaantabelKaartComponentWidgetState
                             children: [
                               Align(
                                 alignment: AlignmentDirectional(0.0, 1.0),
-                                child: ClipRRect(
-                                  borderRadius: BorderRadius.circular(8.0),
-                                  child: CachedNetworkImage(
-                                    fadeInDuration: Duration(milliseconds: 500),
-                                    fadeOutDuration:
-                                        Duration(milliseconds: 500),
-                                    imageUrl: getJsonField(
-                                      evenementenItem,
-                                      r'''$.logo''',
-                                    ).toString(),
-                                    fit: BoxFit.fitHeight,
-                                  ),
+                                child: Builder(
+                                  builder: (context) {
+                                    if (getJsonField(
+                                          evenementenItem,
+                                          r'''$.logo''',
+                                        ) !=
+                                        null) {
+                                      return ClipRRect(
+                                        borderRadius:
+                                            BorderRadius.circular(8.0),
+                                        child: CachedNetworkImage(
+                                          fadeInDuration:
+                                              Duration(milliseconds: 500),
+                                          fadeOutDuration:
+                                              Duration(milliseconds: 500),
+                                          imageUrl: getJsonField(
+                                            evenementenItem,
+                                            r'''$.logo''',
+                                          ).toString(),
+                                          fit: BoxFit.fitHeight,
+                                        ),
+                                      );
+                                    } else {
+                                      return Icon(
+                                        Icons.image_not_supported,
+                                        color: FlutterFlowTheme.of(context)
+                                            .primaryText,
+                                        size: 24.0,
+                                      );
+                                    }
+                                  },
                                 ),
                               ),
                               Align(

+ 31 - 12
lib/uitgaanspaginas/p_uitgaantabel_kaart_component/p_uitgaantabel_kaart_component_widget.dart

@@ -216,18 +216,37 @@ class _PUitgaantabelKaartComponentWidgetState
                             children: [
                               Align(
                                 alignment: AlignmentDirectional(0.0, 1.0),
-                                child: ClipRRect(
-                                  borderRadius: BorderRadius.circular(8.0),
-                                  child: CachedNetworkImage(
-                                    fadeInDuration: Duration(milliseconds: 500),
-                                    fadeOutDuration:
-                                        Duration(milliseconds: 500),
-                                    imageUrl: getJsonField(
-                                      evenementenItem,
-                                      r'''$.logo''',
-                                    ).toString(),
-                                    fit: BoxFit.fitHeight,
-                                  ),
+                                child: Builder(
+                                  builder: (context) {
+                                    if (getJsonField(
+                                          evenementenItem,
+                                          r'''$.logo''',
+                                        ) !=
+                                        null) {
+                                      return ClipRRect(
+                                        borderRadius:
+                                            BorderRadius.circular(8.0),
+                                        child: CachedNetworkImage(
+                                          fadeInDuration:
+                                              Duration(milliseconds: 500),
+                                          fadeOutDuration:
+                                              Duration(milliseconds: 500),
+                                          imageUrl: getJsonField(
+                                            evenementenItem,
+                                            r'''$.logo''',
+                                          ).toString(),
+                                          fit: BoxFit.fitHeight,
+                                        ),
+                                      );
+                                    } else {
+                                      return Icon(
+                                        Icons.image_not_supported,
+                                        color: FlutterFlowTheme.of(context)
+                                            .primaryText,
+                                        size: 24.0,
+                                      );
+                                    }
+                                  },
                                 ),
                               ),
                               Align(