diff --git a/feature/shares/.gitignore b/feature/shares/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/feature/shares/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/shares/README.md b/feature/shares/README.md
new file mode 100644
index 0000000000..11dd15087f
--- /dev/null
+++ b/feature/shares/README.md
@@ -0,0 +1,3 @@
+# :feature:shares module
+## Dependency graph
+// need to create --> 
\ No newline at end of file
diff --git a/feature/shares/build.gradle.kts b/feature/shares/build.gradle.kts
new file mode 100644
index 0000000000..60244c3e63
--- /dev/null
+++ b/feature/shares/build.gradle.kts
@@ -0,0 +1,46 @@
+@Suppress("DSL_SCOPE_VIOLATION")
+plugins {
+ id("mifos.cmp.feature")
+}
+
+android {
+ namespace = "com.mifos.androidclient.features.shares"
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.jb.lifecycleViewmodel)
+ api(projects.core.model)
+ api(projects.core.common)
+ }
+
+ androidMain.dependencies {
+ implementation(libs.androidx.core.ktx)
+ }
+ }
+}
+dependencies {
+ implementation(projects.cmpShared)
+ implementation(projects.core.ui)
+ implementation(projects.core.domain)
+ implementation(projects.core.designsystem)
+ implementation(projects.core.datastore)
+ implementation(projects.core.network)
+ implementation(projects.core.database)
+ implementation(libs.androidx.navigation.fragment)
+ implementation(libs.androidx.navigation.ui)
+ implementation(libs.hilt.android)
+ kapt(libs.hilt.compiler)
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.jb.lifecycleViewmodel)
+ implementation(libs.jb.lifecycleruntime)
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.kotlinx.coroutines.android)
+ implementation(libs.androidx.recyclerview)
+ implementation(libs.google.material)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.test.ext)
+ androidTestImplementation(libs.espresso.core)
+}
\ No newline at end of file
diff --git a/feature/shares/consumer-rules.pro b/feature/shares/consumer-rules.pro
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/shares/proguard-rules.pro b/feature/shares/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/feature/shares/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/AndroidManifest.xml b/feature/shares/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000000..a71b693fa9
--- /dev/null
+++ b/feature/shares/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/Charge.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/Charge.kt
new file mode 100644
index 0000000000..0e1bd63520
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/Charge.kt
@@ -0,0 +1,12 @@
+package com.mifos.androidclient.features.shares.data.models
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Charge(
+ val title: String,
+ val type: String,
+ val collectedOn: String,
+ val amount: String
+) : Parcelable
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/ShareAccountData.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/ShareAccountData.kt
new file mode 100644
index 0000000000..9d33c5cec5
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/data/models/ShareAccountData.kt
@@ -0,0 +1,20 @@
+package com.mifos.androidclient.features.shares.data.models
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class ShareAccountData(
+ val productName: String,
+ val externalId: String,
+ val submittedDate: String,
+ val currency: String,
+ val currentPrice: String,
+ val totalNumberOfShares: String,
+ val defaultSavingsAccount: String,
+ val applicationDate: String,
+ val allowDividends: Boolean,
+ val minimumActivePeriod: String,
+ val lockInPeriod: String,
+ val charges: List
+) : Parcelable
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ChargesAdapter.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ChargesAdapter.kt
new file mode 100644
index 0000000000..f6b13553fb
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ChargesAdapter.kt
@@ -0,0 +1,41 @@
+package com.mifos.androidclient.features.shares.preview
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.mifos.androidclient.databinding.ItemChargeBinding
+import com.mifos.androidclient.features.shares.data.models.Charge
+
+class ChargesAdapter : ListAdapter(ChargeDiffCallback()) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChargeViewHolder {
+ val binding = ItemChargeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return ChargeViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: ChargeViewHolder, position: Int) {
+ val charge = getItem(position)
+ holder.bind(charge)
+ }
+
+ class ChargeViewHolder(private val binding: ItemChargeBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+
+ fun bind(charge: Charge) {
+ binding.chargeTitleTv.text = charge.title
+ binding.chargeAmountTv.text = charge.amount
+ }
+ }
+}
+
+class ChargeDiffCallback : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Charge, newItem: Charge): Boolean {
+ return oldItem.title == newItem.title && oldItem.amount == newItem.amount
+ }
+
+ override fun areContentsTheSame(oldItem: Charge, newItem: Charge): Boolean {
+ return oldItem == newItem
+ }
+}
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountCreationViewModel.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountCreationViewModel.kt
new file mode 100644
index 0000000000..76e2d86a7e
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountCreationViewModel.kt
@@ -0,0 +1,46 @@
+package com.mifos.androidclient.features.shares.preview
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.mifos.androidclient.features.shares.data.models.Charge
+import com.mifos.androidclient.features.shares.data.models.ShareAccountData
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+class ShareAccountCreationViewModel : ViewModel() {
+
+ private val _shareAccountData = MutableStateFlow(null)
+ val shareAccountData: StateFlow = _shareAccountData.asStateFlow()
+
+ fun updateShareAccountData(data: ShareAccountData) {
+ _shareAccountData.value = data
+ }
+
+ fun populateWithMockData() {
+ val mockData = ShareAccountData(
+ productName = "Wallet",
+ externalId = "33333",
+ submittedDate = "09 June 2025",
+ currency = "USD",
+ currentPrice = "$10,000",
+ totalNumberOfShares = "10",
+ defaultSavingsAccount = "Nobi",
+ applicationDate = "26-09-2025",
+ allowDividends = true,
+ minimumActivePeriod = "2 Months",
+ lockInPeriod = "6 Weeks",
+ charges = listOf(
+ Charge("Savings Administration", "Flat", "10-06-2025", "$2"),
+ Charge("Account Opening Fee", "Flat", "26-09-2025", "$5")
+ )
+ )
+ _shareAccountData.value = mockData
+ }
+
+ fun submitNewShareAccount() {
+ viewModelScope.launch {
+ }
+ }
+}
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountPreviewFragment.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountPreviewFragment.kt
new file mode 100644
index 0000000000..659cb96b7c
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ShareAccountPreviewFragment.kt
@@ -0,0 +1,88 @@
+package com.mifos.androidclient.features.shares.preview
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.mifos.androidclient.databinding.FragmentShareAccountPreviewBinding
+import com.mifos.androidclient.features.shares.data.models.ShareAccountData
+
+class ShareAccountPreviewFragment : Fragment() {
+
+ private var _binding: FragmentShareAccountPreviewBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: ShareAccountCreationViewModel by activityViewModels()
+ private val chargesAdapter = ChargesAdapter()
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentShareAccountPreviewBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ // For isolated testing, populate the ViewModel with mock data.
+ // Remove this line once the previous steps are implemented and passing data.
+ viewModel.populateWithMockData()
+
+ binding.chargesRv.apply {
+ layoutManager = LinearLayoutManager(context)
+ adapter = chargesAdapter
+ }
+
+ viewModel.shareAccountData.observe(viewLifecycleOwner) { data ->
+ data?.let {
+ updateUI(it)
+ chargesAdapter.submitList(it.charges)
+ }
+ }
+
+ binding.backBtn.setOnClickListener {
+ findNavController().popBackStack()
+ }
+
+ binding.nextBtn.setOnClickListener {
+ if (viewModel.shareAccountData.value != null) {
+ viewModel.submitNewShareAccount()
+ } else {
+ Toast.makeText(context, "Data is missing. Please go back to previous steps.", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ binding.viewChargesBtn.setOnClickListener {
+ val charges = viewModel.shareAccountData.value?.charges ?: emptyList()
+ ViewChargesBottomSheetFragment.newInstance(charges).show(
+ childFragmentManager, "ViewChargesModal"
+ )
+ }
+ }
+
+ private fun updateUI(data: ShareAccountData) {
+ binding.productNameTv.text = "Product Name: ${data.productName}"
+ binding.externalIdTv.text = "External ID: ${data.externalId}"
+ binding.submittedDateTv.text = "Submitted Date: ${data.submittedDate}"
+
+ binding.currencyTv.text = "Currency: ${data.currency}"
+ binding.currentPriceTv.text = "Current Price: ${data.currentPrice}"
+ binding.totalSharesTv.text = "Total Shares: ${data.totalNumberOfShares}"
+ binding.defaultSavingsAccountTv.text = "Default Savings Account: ${data.defaultSavingsAccount}"
+ binding.applicationDateTv.text = "Application Date: ${data.applicationDate}"
+ binding.allowDividendsTv.text = "Allow Dividends: ${if (data.allowDividends) "Yes" else "No"}"
+ binding.minimumActivePeriodTv.text = "Minimum Active Period: ${data.minimumActivePeriod}"
+ binding.lockInPeriodTv.text = "Lock-in Period: ${data.lockInPeriod}"
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ViewChargesBottomSheetFragment.kt b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ViewChargesBottomSheetFragment.kt
new file mode 100644
index 0000000000..e0b364a41f
--- /dev/null
+++ b/feature/shares/src/androidMain/kotlin/com/mifos/feature/shares/preview/ViewChargesBottomSheetFragment.kt
@@ -0,0 +1,56 @@
+package com.mifos.androidclient.features.shares.preview
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.os.bundleOf
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import com.mifos.androidclient.databinding.BottomSheetViewChargesBinding
+import com.mifos.androidclient.features.shares.data.models.Charge
+
+class ViewChargesBottomSheetFragment : BottomSheetDialogFragment() {
+
+ private var _binding: BottomSheetViewChargesBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = BottomSheetViewChargesBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val charges = arguments?.getParcelableArrayList(CHARGES_KEY) ?: emptyList()
+ val adapter = ChargesAdapter()
+ binding.chargesListRv.apply {
+ layoutManager = LinearLayoutManager(context)
+ this.adapter = adapter
+ }
+ adapter.submitList(charges)
+
+ binding.cancelBtn.setOnClickListener {
+ dismiss()
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+ companion object {
+ const val CHARGES_KEY = "charges_key"
+
+ fun newInstance(charges: List): ViewChargesBottomSheetFragment {
+ return ViewChargesBottomSheetFragment().apply {
+ arguments = bundleOf(CHARGES_KEY to ArrayList(charges))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/shares/src/androidMain/res/layout/bottom_sheet_view_charges.xml b/feature/shares/src/androidMain/res/layout/bottom_sheet_view_charges.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/shares/src/androidMain/res/layout/fragment_share_account_preview.xml b/feature/shares/src/androidMain/res/layout/fragment_share_account_preview.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/shares/src/androidMain/res/layout/item_charge.xml b/feature/shares/src/androidMain/res/layout/item_charge.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/feature/shares/src/androidMain/res/values/feature_shares_strings.xml b/feature/shares/src/androidMain/res/values/feature_shares_strings.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/settings.gradle.kts b/settings.gradle.kts
index dff5de1de1..21b3469039 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -96,3 +96,4 @@ include(":feature:search")
include(":feature:settings")
//include(":feature:passcode")
include(":feature:search")
+include(":feature:shares")