Skip to content

Instantly share code, notes, and snippets.

@oyewalekehinde
Created November 2, 2024 23:47
Show Gist options
  • Select an option

  • Save oyewalekehinde/623375425fd3c557adee0e747ad53a2f to your computer and use it in GitHub Desktop.

Select an option

Save oyewalekehinde/623375425fd3c557adee0e747ad53a2f to your computer and use it in GitHub Desktop.
httpservice
class HttpService {
Dio? _dio;
final String baseUrl;
final bool hasAuthorization;
final bool isFormType;
HttpService(
{required this.baseUrl,
this.hasAuthorization = false,
this.isFormType = false}) {
_dio = Dio(BaseOptions(
baseUrl: baseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 8),
));
_interceptorsInit();
}
static const int timeoutDuration = 1;
Future<Response> getRequest(
urlEndPoint, {
Map<String, dynamic>? queryParameters,
}) async {
Response response;
if (kDebugMode) log(urlEndPoint);
response = await _dio!
.get(urlEndPoint, queryParameters: queryParameters)
.timeout(const Duration(minutes: timeoutDuration));
if(response.statusCode==401){
}
return response;
}
Future<Response> post(
urlEndpoint, {
data,
Map<String, dynamic>? queryParameters,
}) async {
Response response;
if (kDebugMode) log(urlEndpoint.toString());
response = await _dio!
.post(urlEndpoint, data: data, queryParameters: queryParameters)
.timeout(const Duration(minutes: timeoutDuration));
return response;
}
Future<Response> put(urlEndpoint,
{data, Map<String, dynamic>? queryParameters}) async {
Response response;
response = await _dio!
.put(urlEndpoint, data: data, queryParameters: queryParameters)
.timeout(const Duration(minutes: timeoutDuration));
return response;
}
Future<Response> delete(urlEndpoint,
{data, Map<String, dynamic>? queryParameters}) async {
Response response;
response = await _dio!
.delete(urlEndpoint, data: data, queryParameters: queryParameters)
.timeout(const Duration(minutes: timeoutDuration));
return response;
}
Future<Response> patch(urlEndpoint,
{data, Map<String, dynamic>? queryParameters}) async {
Response response;
response = await _dio!
.patch(urlEndpoint, data: data, queryParameters: queryParameters)
.timeout(const Duration(minutes: timeoutDuration));
return response;
}
_interceptorsInit() {
_dio!.interceptors.add(HeaderInterceptor(
hasToken: hasAuthorization,
dio: _dio!,
contentType: isFormType
? HeaderContentType.formType
: HeaderContentType.jsonType));
}
}
@muzz-code
Copy link

muzz-code commented Nov 5, 2024

i dey manage the state on this notifier class 

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:u_360_v2_mobile_app/beneficiary_management/models/BeneficiaryManagementItemList.dart';
import 'package:uuid/uuid.dart';

import '../../transfer/models/beneficiary_state.dart';

class BeneficiaryManagementNotifier extends StateNotifier<List<BeneficiaryState>> {
  BeneficiaryManagementNotifier() : super([]);

  final uuid = const Uuid();

  void addBeneficiary({
    required String bankName,
    required String beneficiaryAccountNumber,
    required String beneficiaryAccountName,
    required String bankCode,
    required String accountCurrency,
    required String corporateName,
  }) {
    state = [
      ...state,
      BeneficiaryState(
        corpId: uuid.v4(),
        subsidiaryId: null,
        beneficiaryAccountName: beneficiaryAccountName,
        beneficiaryAccountNumber: beneficiaryAccountNumber,
        unionAccount: false,
        bankName: bankName,
        userId: null,
        bankCode: bankCode,
        accountCurrency: accountCurrency,
        corporateName: corporateName,
        beneficiaryId: state.length + 1, // or generate a unique ID as needed
      )
    ];
  }

  void deleteBeneficiary(String corpId) {
    state = state.where((item) => item.corpId != corpId).toList();
  }

  void clearBeneficiaries() {
    state = [];
  }

  List<BeneficiaryState> getAllBeneficiaries() {
    return state;
  }

  // New method to search beneficiaries by a term
  List<BeneficiaryState> searchBeneficiaries(String searchTerm) {
    return state.where((beneficiary) {
      final lowerCaseTerm = searchTerm.toLowerCase();
      return (beneficiary.bankName?.toLowerCase().contains(lowerCaseTerm) ?? false) ||
          (beneficiary.beneficiaryAccountNumber?.contains(searchTerm) ?? false) ||
          (beneficiary.beneficiaryAccountName?.toLowerCase().contains(lowerCaseTerm) ?? false);
    }).toList();
  }
}

final beneficiaryManagementProvider = StateNotifierProvider<
    BeneficiaryManagementNotifier, List<BeneficiaryState>>(
      (ref) => BeneficiaryManagementNotifier(),
);

@muzz-code
Copy link

muzz-code commented Nov 5, 2024

and here also

import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:u_360_v2_mobile_app/beneficiary_management/api/beneficiary_management_api.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/popup_widgets.dart';
import '../../authentication/api_client/auth_api_cient.dart';
import '../../config/config.dart';
import '../../core/common/storage/secure_storage.dart';
import '../../transfer/models/beneficiary_state.dart';
import '../../transfer/single_transfer/api/single_transfer_api.dart';
import '../notifier/beneficiary_management_notifier.dart';

part 'beneficiary_management_controller.g.dart';

final beneficiariesProvider =
StateProvider<List<BeneficiaryState>>((ref) => []);

@riverpod
class BeneficiaryManagementController extends _$BeneficiaryManagementController {
  TextEditingController bankNameController = TextEditingController();
  TextEditingController accountNumberController = TextEditingController();
  TextEditingController accountNameController = TextEditingController();
  TextEditingController bankCodeController = TextEditingController();
  TextEditingController accountCurrencyController = TextEditingController();
  TextEditingController corporateNameController = TextEditingController();

  bool nameEnquiryStatus = false;
  String? beneficiaryAccountName = "";
  final apiClient = ApiClient();
  final beneficiaryManagementApi = BeneficiaryManagementApi();

  void setAccountNumberValue(String beneficiaryAccountNumber, WidgetRef ref) {
    ref.read(accountNumberProvider.notifier).state = beneficiaryAccountNumber;
  }

  // Initialize with an empty instance of BeneficiaryState
  @override
  BeneficiaryState build() {
    return BeneficiaryState();
  }

  Future<String?> fetchCorporateAccountName({
    required String accountNumber,
    WidgetRef? ref,
    String? bankCode,
  }) async {
    if (accountNumber.length == 10 && ref != null) {
      final result = await SingleTransferApi(ref: ref)
          .nameEnquiry(accountNumber: accountNumber, bankCode: bankCode);

      if (hasAuthenticationOrProcessingError(result)) {
        nameEnquiryStatus = true;
      } else if (result?.code == "00") {
        beneficiaryAccountName = result?.accountName;
        nameEnquiryStatus = true;
        return result?.accountName;
      }
    }
    nameEnquiryStatus = true;
    return null;
  }

  Future<void> loadBeneficiaries(WidgetRef ref) async {
    log("Loading beneficiaries");
    var userResponse = await Storage.loadUserProfile();
    var userCorpId = userResponse?.corpId;
    var userSubsidiaryId = userResponse?.subsidiaryId;
    var beneficiaryWithCorpIdPayload = {
      "corpId": userCorpId,
      "subsidiaryId": userSubsidiaryId,
      "userId": '13'
    };

    var beneficiariesResponse = await apiClient.postCustomRequest(
      Config.getBeneficiariesByCorpId ?? "",
      beneficiaryWithCorpIdPayload,
    );
    final beneficiaries = (beneficiariesResponse.data as List<dynamic>)
        .map((item) => BeneficiaryState.fromJson(item as Map<String, dynamic>))
        .toList();
    ref.read(beneficiariesProvider.notifier).state = beneficiaries;
  }

  Future<void> addBeneficiaries({
    required WidgetRef ref,
    BuildContext? context,
    BeneficiaryManagementNotifier? beneficiaryNotifier,
    String? beneficiaryAccountName,
    String? bankCode,
  }) async {
    final accountNumber = ref.read(accountNumberProvider);
    try {
      await beneficiaryManagementApi.addBeneficiary(
        bankName: bankNameController.text,
        beneficiaryAccountNumber: accountNumber,
        beneficiaryAccountName: accountNameController.text,
        accountCurrency: accountCurrencyController.text,
        bankCode: bankCodeController.text,
      );

      // Reload beneficiaries after adding a new one to update the UI
      await loadBeneficiaries(ref);
    } catch (e) {
      toastInfo("An error occurred");
      log("An error occurred: $e");
    }
  }

  Future<void> deleteBeneficiaries({
    required int? beneficiaryId,
    required WidgetRef ref,
  }) async {
    await beneficiaryManagementApi.deleteBeneficiary(
      beneficiaryId: beneficiaryId ?? 0,
    );
    await loadBeneficiaries(ref);
  }
}

@riverpod
class UpdateBeneficiaryController {}

final accountNumberProvider = StateProvider<String>((ref) => "");

bool hasAuthenticationOrProcessingError(dynamic result) {
  return result?.message == "Authentication Failed" ||
      result?.message == "Error processing request" ||
      result?.code == "401" ||
      result?.code == "96";
}

@muzz-code
Copy link

muzz-code commented Nov 5, 2024

i dey read the value for this widget

`import 'dart:developer';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:u_360_v2_mobile_app/authentication/sign_up/notifier/sign_up_notifier.dart';
import 'package:u_360_v2_mobile_app/beneficiary_management/controller/beneficiary_management_controller.dart';
import 'package:u_360_v2_mobile_app/core/common/models/banks.dart';
import 'package:u_360_v2_mobile_app/core/common/utils/image_res.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/app_shadow.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/app_textfields.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/button_widgets.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/image_widgets.dart';
import 'package:u_360_v2_mobile_app/core/common/widgets/text_widgets.dart';
import 'package:u_360_v2_mobile_app/transfer/provider/name_enquiry_provider.dart';

import '../../../authentication/login/controller/custom_api_controller.dart';
import '../../../authentication/widgets/decorated_container.dart';
import '../../../core/common/provider/global_loader.dart';
import '../../../core/constants/colors.dart';
import '../../../transfer/widgets/transfer_widgets.dart';
import '../../notifier/beneficiary_management_notifier.dart';

class BeneficiaryItems extends ConsumerStatefulWidget {
  const BeneficiaryItems({super.key});

  @override
  ConsumerState<BeneficiaryItems> createState() => _BeneficiaryItemsState();
}

class _BeneficiaryItemsState extends ConsumerState<BeneficiaryItems> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final beneficiaryState = ref.watch(beneficiaryStateNotifierProvider);
    final loader = ref.watch(appLoaderProvider);

    return beneficiaryState.when(
        data: (data) => ListView.builder(
              padding: EdgeInsets.zero,
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: data.length,
              itemBuilder: (context, index) {
                return Padding(
                  padding:
                      const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0),
                  child: Container(
                    decoration: appBoxDecorationTextField(),
                    child: Padding(
                      padding: const EdgeInsets.all(18.0),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Flexible(
                            flex: 1,
                            child: Align(
                              alignment: Alignment.topLeft,
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  SizedBox(
                                    width:
                                        MediaQuery.of(context).size.width * 0.5,
                                    child: text14Normal(
                                      text:
                                          data[index].beneficiaryAccountName ??
                                              "",
                                      color: AppColors.black,
                                    ),
                                  ),
                                  const SizedBox(height: 15),
                                  text14Medium(
                                    text:
                                        data[index].beneficiaryAccountNumber ??
                                            "",
                                    color: AppColors.black,
                                  ),
                                ],
                              ),
                            ),
                          ),
                          Flexible(
                            flex: 1,
                            child: Align(
                              alignment: Alignment.topRight,
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.end,
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  GestureDetector(
                                    child: text14Medium(text: "..."),
                                    onTap: () {
                                      displayDeleteBottomSheet(
                                        context: context,
                                        ref: ref,
                                        beneficiaryId:
                                            data[index].beneficiaryId,
                                      );
                                    },
                                  ),
                                  const SizedBox(height: 15),
                                  SizedBox(
                                    width:
                                        MediaQuery.of(context).size.width * 0.5,
                                    child: text14Normal(
                                      isEndText: true,
                                      text: data[index].bankName ?? "",
                                      color: AppColors.black,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                );
              },
            ),
        error: (err, stackTrace) {
          log("error message: $err");
          log("stack trace message: $err");
          return text14Bold(text: "Error Loading Page");
        },
        loading: () => const Center(child: CircularProgressIndicator()));
  }
}

Future displayDeleteBottomSheet({
  required BuildContext context,
  required WidgetRef ref,
  required int? beneficiaryId,
}) {
  return showModalBottomSheet(
    context: context,
    isDismissible: false,
    enableDrag: false,
    builder: (context) => Container(
      constraints: const BoxConstraints(
        maxHeight: 500,
      ),
      width: double.infinity,
      padding: const EdgeInsets.all(16.0),
      child: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const SizedBox(height: 20),
            appImage(
              imagePath: ImageRes.errorLargeIcon,
              height: 70,
              width: 70,
            ),
            const SizedBox(height: 20),
            text16BoldCenter(text: "Confirm Action", isCenterText: true),
            text14Normal(
              text: "Are you sure you want to delete this beneficiary?",
            ),
            const SizedBox(height: 20),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 28.0),
              child: Row(
                children: [
                  Expanded(
                    child: AppButton(
                      buttonTextColor: AppColors.black,
                      buttonColor: AppColors.greyCard,
                      buttonName: "Cancel",
                      height: 45,
                      extraCornerRadius: true,
                      isButtonPair: true,
                      func: () {
                        Navigator.pop(context);
                      },
                    ),
                  ),
                  const SizedBox(width: 20),
                  Expanded(
                    child: AppButton(
                      buttonTextColor: AppColors.whiteColor,
                      buttonName: "Yes, Delete",
                      extraCornerRadius: true,
                      height: 45,
                      isButtonPair: true,
                      func: () {
                        ref
                            .watch(beneficiaryManagementControllerProvider
                                .notifier)
                            .deleteBeneficiaries(
                                beneficiaryId: beneficiaryId, ref: ref);
                        ref
                            .read(beneficiaryManagementControllerProvider
                                .notifier)
                            .loadBeneficiaries(ref);
                        Navigator.pop(context);
                      },
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    ),
  );
}

Future displayApprovedBottomSheet(
    {required BuildContext context,
    required WidgetRef ref,
    required Function() setStateFunc}) {
  final beneficiaryName =
      ref.watch(beneficiaryManagementControllerProvider).beneficiaryAccountName;
  return showModalBottomSheet(
      context: context,
      isDismissible: false,
      enableDrag: false,
      builder: (context) => Container(
          constraints: const BoxConstraints(
            maxHeight: 500,
          ),
          width: double.infinity,
          padding: const EdgeInsets.all(16.0),
          child: SingleChildScrollView(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const SizedBox(height: 20),
              text16BoldCenter(text: "Add Beneficiary", isCenterText: true),
              const SizedBox(height: 20),
              appImage(
                  imagePath: ImageRes.successLargeIcon, height: 80, width: 80),
              const SizedBox(height: 20),
              text16BoldCenter(
                  text: "Beneficiary Added Successfully", isCenterText: true),
              text14Normal(
                  text:
                      "$beneficiaryName has been added successfully as your beneficiary",
                  isCenterText: true),
              const SizedBox(height: 20),
              AppButton(
                buttonWidth: 50,
                buttonName: "Close",
                func: setStateFunc,
              ),
              const SizedBox(height: 20),
            ],
          ))));
}

Future displayBottomSheet(
    {required BuildContext context,
    required WidgetRef ref,
    String? dropdownValue1,
    AsyncValue<List<GETBANKLISTITEM>>? bankListAsyncState,
    TextEditingController? accountNumberController,
    required Function() setStateFunc}) {
  final beneficiaryManagementNotifier =
      ref.watch(beneficiaryManagementProvider.notifier);
  return showModalBottomSheet(
    context: context,
    isDismissible: false,
    enableDrag: false,
    builder: (context) => Container(
      constraints: const BoxConstraints(
        maxHeight: 500,
      ),
      width: double.infinity,
      padding: const EdgeInsets.all(16.0),
      child: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            bankListAsyncState?.when(
                  data: (data) => transferDropdownContainer<GETBANKLISTITEM>(
                    headerText: "Bank name",
                    hintText: '-select bank-',
                    dropdownValue: dropdownValue1 ?? "",
                    onChanged: (value) {
                      GETBANKLISTITEM? selectedItem = data.firstWhere(
                        (item) => item.bNKNAME == value,
                        orElse: () => GETBANKLISTITEM(),
                      );
                      var bankCode = selectedItem.bNKCODE;
                      var bankName = selectedItem.bNKNAME;
                    },
                    asyncList: bankListAsyncState,
                  ),
                  error: (error, stackTrace) =>
                      const Center(child: Text("Error loading data")),
                  loading: () => buildCustomCircularProgressIndicator(),
                ) ??
                const SizedBox(height: 10),
            const SizedBox(height: 20),
            appTextField<String>(
              hintText: "Account Number",
              textFieldHeight: 45,
              textWidget: text12Normal(text: "Account num"),
              paddingLeft: 0,
              paddingRight: 0,
              isAccountNumber: true,
              isNumberKeyboard: true,
              controller: accountNumberController,
              isPostFailureFixIconEnabled: (ref
                          .watch(nameEnquiryProvider.notifier)
                          .nameEnquiryStatus ??
                      false) &&
                  ref
                      .watch(beneficiaryManagementControllerProvider.notifier)
                      .accountNumberController
                      .text
                      .isEmpty,
              isPostSuccessFixIconEnabled: (ref
                          .watch(nameEnquiryProvider.notifier)
                          .nameEnquiryStatus ??
                      false) &&
                  ref
                      .watch(beneficiaryManagementControllerProvider.notifier)
                      .accountNumberController
                      .text
                      .isNotEmpty,
              func: (value) {
                if (value.length == 10) {
                  ref
                      .read(beneficiaryManagementControllerProvider.notifier)
                      .setAccountNumberValue(value, ref);
                  ref
                      .read(beneficiaryManagementControllerProvider.notifier)
                      .fetchCorporateAccountName(
                          accountNumber: value, ref: ref);
                }
              },
            ),
            const SizedBox(height: 20),
            appTextField(
                textWidget: text12Normal(text: "Account name"),
                text: "Account Name",
                backgroundColor: AppColors.skyBlueBackground,
                controller: ref
                    .watch(corporateProfileStateNotifierProvider.notifier)
                    .corporateAccountEmailController,
                readOnly: true,
                textFieldHeight: 45,
                hintText: "Account Name",
                paddingLeft: 0,
                paddingRight: 0),
            const SizedBox(height: 20),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 28.0),
              child: Row(
                children: [
                  Expanded(
                    child: AppButton(
                        buttonTextColor: AppColors.black,
                        buttonColor: AppColors.greyCard,
                        buttonName: "Cancel",
                        height: 45,
                        extraCornerRadius: true,
                        isButtonPair: true,
                        func: () {
                          accountNumberController?.text = "";
                          Navigator.pop(context);
                        }),
                  ),
                  const SizedBox(width: 20),
                  Expanded(
                    child: AppButton(
                      buttonTextColor: AppColors.whiteColor,
                      buttonName: "Save",
                      extraCornerRadius: true,
                      height: 45,
                      isButtonPair: true,
                      func: () async {
                        await displayApprovedBottomSheet(
                            context: context,
                            ref: ref,
                            setStateFunc: setStateFunc);
                        ref
                            .watch(beneficiaryManagementControllerProvider
                                .notifier)
                            .addBeneficiaries(
                                ref: ref,
                                context: context,
                                beneficiaryNotifier:
                                    beneficiaryManagementNotifier);
                        ref.refresh(beneficiaryStateNotifierProvider);
                        accountNumberController?.text = "";
                        Navigator.pop(context);
                      },
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    ),
    barrierColor: Colors.black.withOpacity(0.5),
    backgroundColor: Colors.white,
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)),
    ),
  );
}
`

@oyewalekehinde
Copy link
Author

if (response.statusCode == 401 || response.statusCode == 403) {
      // call refresh token function
      try {
        final refreshResponse = await _dio!.get(
          'https://api.example.com/refresh',
          data: {'refresh_token': ""},
        );
        if (response.statusCode == 200) {
          final newAccessToken = response.data['access_token'];
          await UserTokenManager.insertAccessToken(newAccessToken);
          Response newResponse = await _dio!
              .get(urlEndPoint, queryParameters: queryParameters)
              .timeout(const Duration(minutes: timeoutDuration));
          response = newResponse;
        }
      } catch (e) {
        throw Exception();
      }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment