Skip to content

Ssimboss/BankChallenge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 

Repository files navigation

BankChallenge

Andrei Simvolokov ssimboss@gmail.com Technical Challenge up for a round-up bank feature

Project configuration

The App is written using XCode 26.1 and Swift 6.0 to work on iOS 26.1. Then downgraded to XCode 16.2 and iOS 18.2(see the latest commits). All the code is written using UIKit for UI-level. The code uses the patterns and API of the modern Swift Concurrency paradigm.

Before you start

The App does not have an implementation of OAuth and does not automatically refresh its tokens. Instead, it completely relies on hardcoded Access.accessToken. Please configure this property first. Otherwise the App would block your user experience.

Main features

The App contains a few screens.

"Your Accounts"

This is a start screen. It loads and displays user's accounts as a list. Supports zero case and failed-to-load state. Use pull-to-refresh to completely reload the list. Tap any account to proceed to "Account" screen

"Account"

This is an account summary. It displays the balance, the list of Saving Goals and the list of Recent transactions(Transactions for the last 10 days). Supports zero cases and failed-to-load states. Use pull-to-refresh to completely reload the content. Use the "+" button in Saving Goal's header to proceed to the "Create Savings goal" screen. If you have at least one goal, tap on its cell to proceed to the "Saving Goal" screen.

"Create Savings goal"

This is an input-form to create a new goal. Provide a name for a goal and the target amount in the text-field and tap the "Create goal" button to initiate a process. Supports basic validation: button is disabled whenever goal's name is empty or the goal's target is zero. The "amount" text-field supports the basic formatting checks to prevent non-appropriate input.

"Savings goal"

This is a screen showing basic Savings Goal's details. Tap "Add round-ups!" button to proceed to the "Round up" screen. Tap the "Delete Goal" button to initiate goal removal and return to the "Account" screen.

"Round up"

This screen shows a list of transactions on current week(Since Monday for UK, depends on the localisation specifics). The amount of total possible round-ups is displayed in the header. Supports no-transaction case, zero-round-ups and failed-to-load cases. Tap the "Move round-ups to savings" button to initiate a transaction and return to the "Account" screen.

Additional Features

  • Dark Mode support
  • Localisation: English and Russian
  • Accessibility: Voice Over A11y labels and A11y identifiers for 3rd party QA tools
  • Liquid glass icon

Project structure

The App project contains next domains:

Resources

These are all the resources consumed by the App: localisations, assets(colors and images), AppIcon.

Views

This is all the code related to the View-Level of the App. All the View-Controllers follow the MVVM architecture: they display the values provided by their view-models, observe any changes in the state and provide information about the user's actions back to their view-models.

  • Design.swift. These are global variables containing basic constants of a primitive design-system. Currently it has only a set of colors and fonts.
  • AllAccounts. This is the code responsible for displaying the "All accounts" screen. This folder contains a AllAccountsViewController and the cells it uses.
  • Account. This is the code responsible for displaying the "Account" screen. This folder contains a AccountViewController, the cells and subviews it uses.
  • CreateSavingsGoal. Contains a single CreateSavingsGoalViewController responsible for the "Create Savings goal" screen.
  • SavingGoal. Contains a single SavingsGoalViewController responsible for the "Savings goal" screen.
  • RoundUp. Contains a single RoundUpViewController responsible for the "Round up" screen.

ScreensLogic

These are all the ViewModels and additional helpers which work on the MainActor/DispatchQueue.main. The structure mirrors the Views. The helpers are:

  • Factory: These are simple classes to construct a specified ViewController.
  • Router: These are simple classes responsible for redirections from particular screens

The View-Model behaviour described below:

  • AllAccountsViewModel: Observes the list of current accounts and their balances in AccountsService. Uses DataFormatter to display currency-values properly. Forces the update on construction. Forces a complete data-reload on pull-to-refresh. Redirects to accounts screen through its router on account-cell tap. Shows alert via router on appear if the Access.accessToken is not configured.
  • AccountViewModel: Observes the balance of the displayed account in AccountsService, the list of recent transaction in TransactionsService and the list of saving-goals in SavingsGoalsService. Uses DataFormatter to display currency-values and dates properly. Sorts the data-lists before being displayed. Forces a complete data-reload on pull-to-refresh. Redirects to other screens on user actions when needed.
  • CreateSavingsGoalViewModel: Handles the user's input actions and does a primitive data-validation. Enables the CTA state when data is valid. Uses DataFormatter to display currency-values properly. Initiates creation of a Savings Goal with SavingsGoalsService. Dismiss itself using its router.
  • SavingGoalViewModel: Displays data of a selected Saving Goal. Uses DataFormatter to display currency-values properly. Initiates a Savings Goal's deletion on button tap with SavingsGoalsService. Redirects to the "Round Up" screen with the router when needed. Dismiss itself using its router.
  • RoundUpViewModel: Observes the list of weekly transactions in another instance of TransactionsService. Forces the list reload on construction. Sorts data before displaying. Uses DataFormatter to display currency-values properly. Uses SavingsGoalsService to initiate a money-transaction.

Model

This is all the code which is responsible for data and data transformations in the App.

  • DataFormatter.swift: A simple formatter class used by View-Models to properly display currency and date values. Also used to validate the currency-inputs.
  • Foundation: Contains protocols to be used instead of actual Foundation framework instances(FileManager, URLSession). Contains a Loadable type to handle loadable values.
  • Entities: These are all the entity-structures used by the App.
  • Network: Contains a NetworkService. This is a basic class to execute HTTP REST requests.
  • API: Contains a BankAPI. It uses the NetworkService to execute a request of specific domains(AccountsAPI, SavingsGoalAPI, TransactionsAPI).
  • Cache: Contains a generic CacheService to store any kind of Decodable data in a special file on a device.
  • DataServices: Contains services responsible for particular data sets of Model-level. See the details below.

AccountsService

Provides a list of current Accounts. Also provides an AsyncStream to subscribe for any changes in this list. Implements methods to do a hard reloading of the list and soft-update(silence reload without falling in a loading state).

Also provides the balances for the accounts and subscription streams for the balances. Implements methods to do a hard or soft balance reload.

Uses AccountsAPI for remote operations. Stores accounts and balances in two separate instances of CacheService.

SavingsGoalsService

Provides a list of current Saving Goals. Also provides an AsyncStream to subscribe for any changes in this list. Implements methods to do a hard or soft reloading of the list, to create or delete Savings Goals, to move money into Savings Goals.

Uses SavingsGoalAPI for remote operations. Stores the list in an instance of CacheService. Triggers updates of balances, recent transactions and weekly transactions on some operations(Moving money to the Savings Goal, deletion of the Savings Goal).

TransactionsService

Provides a list of transactions. Also provides an AsyncStream to subscribe for any changes in this list. Implements methods to do a hard or soft reloading of the list.

Uses TransactionsAPI for remote operations. Stores the list in an instance of CacheService.

The app has two instances of this class:

  • recentTransactionsService: handles transactions done in the last 10 days.
  • weekTransactionsService: handles transactions done since the beginning of the week(Monday for UK, depends on localisation).

UnitTests

All the classes in the project are written in protocol-based manner to make possible 100% test coverage. However, the project itself misses the init tests for all the components due to lack of time for implementation. Currently there are only some tests to show the basic principles of unit-tests.

The UnitTests host the App itself due to the problems with default project configuration in XCode 26.1.

About

Technical Challenge up for a round-up bank feature

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages