diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fdf8d994a6599dd8b64a341af14c598069a10022..fe63bb677dc7c018519fa0fb0fecb445e5256c67 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="KotlinJpsPluginSettings">
-    <option name="version" value="1.9.0" />
+    <option name="version" value="1.9.23" />
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0ad17cbd33a2f389d524bc4bfef9c52e1f7ab490..8978d23db569daa721cb26dde7923f4c673d1fc9 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ExternalStorageConfigurationManager" enabled="true" />
   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 036f3e83ee280797b2d2fa82b2ce2f1c2ec52912..adfc4c04e01ff796720cc45bd7bd3f6739861ddd 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,7 @@
 plugins {
     alias(libs.plugins.androidApplication)
     alias(libs.plugins.jetbrainsKotlinAndroid)
+    alias(libs.plugins.jetbrainsKotlinKapt)
 }
 
 android {
@@ -33,6 +34,12 @@ android {
     buildFeatures {
         viewBinding = true
     }
+
+    packaging {
+        resources {
+            excludes += "META-INF/*"
+        }
+    }
 }
 
 dependencies {
@@ -45,11 +52,19 @@ dependencies {
     implementation(libs.androidx.lifecycle.viewmodel.ktx)
     implementation(libs.androidx.navigation.fragment.ktx)
     implementation(libs.androidx.navigation.ui.ktx)
+    implementation(libs.androidx.lifecycle.viewmodel.compose)
     implementation(libs.androidx.annotation)
     testImplementation(libs.junit)
     androidTestImplementation(libs.androidx.junit)
     androidTestImplementation(libs.androidx.espresso.core)
 
+    // Room
+    implementation(libs.room.runtime)
+    implementation(libs.room.ktx)
+    implementation(libs.room.common)
+    annotationProcessor(libs.room.compiler)
+    kapt(libs.room.compiler)
+
     // Retrofit
     implementation(libs.retrofit2.retrofit)
     implementation(libs.retrofit2.converter.gson)
@@ -58,4 +73,7 @@ dependencies {
 
     // Work
     implementation(libs.androidx.work.runtime)
+
+    // Excel
+    implementation(libs.excelkt)
 }
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a76744ed0fee6ca61d9a398d985824b3afa9ed2c..a0edab5f4cdbd3e858c3dec4fd20441d0c954598 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,22 +12,34 @@
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
-        android:theme="@style/Theme.Bondoman"
-        tools:targetApi="31">
+        android:theme="@style/Theme.Bondoman">
         <activity
             android:name=".ui.login.LoginActivity"
             android:exported="false"
-            android:label="@string/title_activity_login" />
+            android:label="@string/title_activity_login"
+            android:noHistory="true" />
         <activity
             android:name=".MainActivity"
-            android:exported="true"
-            android:label="@string/app_name">
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity
+            android:name=".AddTransactionActivity"
+            android:exported="false" />
+
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/AddTransactionActivity.kt b/app/src/main/java/com/onionsquad/bondoman/AddTransactionActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e49b61b1892a12f7b0a11a5ec1e4386ab37c519f
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/AddTransactionActivity.kt
@@ -0,0 +1,57 @@
+package com.onionsquad.bondoman
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModelProvider
+import com.onionsquad.bondoman.databinding.ActivityAddTransactionBinding
+import com.onionsquad.bondoman.repository.TransactionRepository
+import com.onionsquad.bondoman.room.TransactionCategory
+import com.onionsquad.bondoman.room.TransactionDatabase
+import com.onionsquad.bondoman.room.TransactionEntity
+import com.onionsquad.bondoman.ui.transaction.TransactionViewModel
+import com.onionsquad.bondoman.ui.transaction.TransactionViewModelFactory
+import java.util.Date
+
+class AddTransactionActivity : AppCompatActivity() {
+    private lateinit var binding: ActivityAddTransactionBinding
+    private val database by lazy { TransactionDatabase.getInstance(this) }
+    private val repository by lazy { TransactionRepository(database.transactionDao()) }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        binding = ActivityAddTransactionBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        val factory = TransactionViewModelFactory(repository)
+        val viewModel = ViewModelProvider(this, factory)[TransactionViewModel::class.java]
+
+        binding.saveButton.setOnClickListener {
+            val title = binding.titleEditText.text.toString()
+            val amount = binding.amountEditText.text.toString().toDoubleOrNull() ?: 0.0
+            val selectedCategoryId = binding.categoryRadioGroup.checkedRadioButtonId
+            val category = when (selectedCategoryId) {
+                R.id.incomeRadioButton -> TransactionCategory.INCOME
+                R.id.outcomeRadioButton -> TransactionCategory.OUTCOME
+                else -> TransactionCategory.OUTCOME
+            }
+            val location = binding.locationEditText.text.toString()
+
+            val currentDate = Date()
+
+            val transaction = TransactionEntity(
+                title = title,
+                amount = amount,
+                category = category,
+                date = currentDate,
+                location = location
+            )
+
+            viewModel.insertTransaction(transaction)
+
+            Intent(this@AddTransactionActivity, MainActivity::class.java).also {
+                startActivity(it)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt b/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
index 5e8bc1e29afe9cefe2d3a0afa6402a29c6d29fab..c0498169e12886585ae46342d9124c1244b72c7f 100644
--- a/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
@@ -23,9 +23,7 @@ class MainActivity : AppCompatActivity() {
         AutoLogoutWorker.start(this)
 
         val sessionManager = SessionManager(this)
-        if (sessionManager.fetchAuthToken() == null) {
-            sendToLoginActivity()
-        }
+        sessionManager.ensureAuthenticated()
 
         binding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(binding.root)
@@ -40,11 +38,4 @@ class MainActivity : AppCompatActivity() {
         setupActionBarWithNavController(navController, appBarConfiguration)
         navView.setupWithNavController(navController)
     }
-
-    private fun sendToLoginActivity() {
-        val intent = Intent(this@MainActivity, LoginActivity::class.java)
-        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK)
-        startActivity(intent)
-        finish()
-    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/auth/SessionManager.kt b/app/src/main/java/com/onionsquad/bondoman/auth/SessionManager.kt
index 91fc448a741643829bf2833dc42eae409ba2ff56..1089d87fad8930e1e229c7f55109bbc33d601161 100644
--- a/app/src/main/java/com/onionsquad/bondoman/auth/SessionManager.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/auth/SessionManager.kt
@@ -1,11 +1,13 @@
 package com.onionsquad.bondoman.auth
 
 import android.content.Context
+import android.content.Intent
 import android.util.Log
 import com.google.gson.Gson
 import com.onionsquad.bondoman.R
+import com.onionsquad.bondoman.ui.login.LoginActivity
 
-class SessionManager(context: Context) {
+class SessionManager(private val context: Context) {
     private val sharedPreferences = context.getSharedPreferences(
         context.getString(R.string.preference_file_key),
         Context.MODE_PRIVATE
@@ -28,4 +30,12 @@ class SessionManager(context: Context) {
     fun deleteAuthToken() {
         sharedPreferences.edit().remove(USER_TOKEN).apply()
     }
+
+    fun ensureAuthenticated() {
+        if (fetchAuthToken() == null) {
+            val intent = Intent(context, LoginActivity::class.java)
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+            context.startActivity(intent)
+        }
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt b/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6d31c4ab7d591d2cb2a82a8c5af4fcd690fbeee8
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt
@@ -0,0 +1,20 @@
+package com.onionsquad.bondoman.repository
+
+import com.onionsquad.bondoman.room.*
+import androidx.lifecycle.LiveData
+
+class TransactionRepository(private val transactionDao: TransactionDao) {
+    val listTransactions: LiveData<List<TransactionEntity>> = transactionDao.getAllTransactions()
+
+    suspend fun insertTransaction(transaction: TransactionEntity) {
+        transactionDao.insertTransaction(transaction)
+    }
+
+    suspend fun updateTransaction(transaction: TransactionEntity) {
+        transactionDao.updateTransaction(transaction)
+    }
+
+    suspend fun deleteTransaction(transaction: TransactionEntity) {
+        transactionDao.deleteTransaction(transaction)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/room/TransactionCategory.kt b/app/src/main/java/com/onionsquad/bondoman/room/TransactionCategory.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f37764b16572f2d510b4d0c2a12c54abae909df7
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/room/TransactionCategory.kt
@@ -0,0 +1,7 @@
+package com.onionsquad.bondoman.room
+
+enum class TransactionCategory {
+    INCOME,
+    OUTCOME,
+    UNKNOWN
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..35e64cc4e012610fb9739a15fc9e6a5132680f45
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt
@@ -0,0 +1,19 @@
+package com.onionsquad.bondoman.room
+
+import androidx.room.*
+import androidx.lifecycle.LiveData
+
+@Dao
+interface TransactionDao {
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    suspend fun insertTransaction(transaction: TransactionEntity)
+
+    @Query("SELECT * FROM transactions")
+    fun getAllTransactions(): LiveData<List<TransactionEntity>>
+
+    @Update
+    suspend fun updateTransaction(transaction: TransactionEntity)
+
+    @Delete
+    suspend fun deleteTransaction(transaction: TransactionEntity)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/room/TransactionDatabase.kt b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDatabase.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dc1fa967766e53114c2fdc3893feff5bc23a4546
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDatabase.kt
@@ -0,0 +1,29 @@
+package com.onionsquad.bondoman.room
+
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import android.content.Context
+
+
+@Database(entities = [TransactionEntity::class], version = 1)
+abstract class TransactionDatabase : RoomDatabase() {
+    abstract fun transactionDao(): TransactionDao
+
+    companion object {
+        @Volatile
+        private var instance: TransactionDatabase? = null
+        fun getInstance(context: Context): TransactionDatabase {
+            synchronized(this) {
+                if (instance == null) {
+                    instance = Room.databaseBuilder(
+                        context.applicationContext,
+                        TransactionDatabase::class.java,
+                        "transaction_database"
+                    ).build()
+                }
+                return instance!!
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/room/TransactionEntity.kt b/app/src/main/java/com/onionsquad/bondoman/room/TransactionEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..64898cbf7c8ebf97163227d9ddd15a23450d0bc8
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/room/TransactionEntity.kt
@@ -0,0 +1,30 @@
+package com.onionsquad.bondoman.room
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import androidx.room.ColumnInfo
+import androidx.room.TypeConverters
+import com.onionsquad.bondoman.util.Converters
+import java.util.Date
+
+@Entity(tableName = "transactions")
+@TypeConverters(Converters::class)
+data class TransactionEntity(
+    @PrimaryKey(autoGenerate = true)
+    val id: Int = 0,
+
+    @ColumnInfo(name = "title")
+    val title: String,
+
+    @ColumnInfo(name = "amount")
+    val amount: Double,
+
+    @ColumnInfo(name = "category")
+    val category: TransactionCategory,
+
+    @ColumnInfo(name = "date", defaultValue = "CURRENT_TIMESTAMP")
+    val date: Date,
+
+    @ColumnInfo(name = "location")
+    val location: String
+)
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt b/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
index 37c78c8c5c0b91cfcb6ee44ff9bbde80ab9e6751..25a006159c73320ffb24bc1e40df328bb90ce677 100644
--- a/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
@@ -1,23 +1,72 @@
 package com.onionsquad.bondoman.ui.settings
 
 import android.app.AlertDialog
+import android.content.Intent
+import android.net.Uri
 import android.os.Bundle
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ArrayAdapter
 import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
+import androidx.core.content.FileProvider
+import androidx.core.net.toUri
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
 import com.onionsquad.bondoman.R
 import com.onionsquad.bondoman.auth.AutoLogoutWorker
 import com.onionsquad.bondoman.auth.SessionManager
 import com.onionsquad.bondoman.databinding.FragmentSettingsBinding
+import com.onionsquad.bondoman.repository.TransactionRepository
+import com.onionsquad.bondoman.room.TransactionCategory
+import com.onionsquad.bondoman.room.TransactionDatabase
+import com.onionsquad.bondoman.room.TransactionEntity
+import io.github.evanrupert.excelkt.workbook
+import org.apache.poi.ss.usermodel.FillPatternType
+import org.apache.poi.ss.usermodel.IndexedColors
+import java.io.File
+import java.io.OutputStream
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import kotlin.io.path.createTempFile
 
 class SettingsFragment : Fragment() {
     private var _binding: FragmentSettingsBinding? = null
 
     private val binding get() = _binding!!
 
+    private val database by lazy { TransactionDatabase.getInstance(requireContext()) }
+    private val repository by lazy { TransactionRepository(database.transactionDao()) }
+
+
+    private val saveXls =
+        registerForActivityResult(CreateDocument("application/vnd.ms-excel")) { uri ->
+            if (uri != null) {
+                repository.listTransactions.observe(viewLifecycleOwner) { list ->
+                    Log.d(this::class.java.simpleName, "Saving transactions to $uri")
+                    requireContext().contentResolver.openOutputStream(uri)?.use { fos ->
+                        createExcelFile(list, fos)
+                    }
+                }
+            }
+        }
+
+    private val saveXlsx =
+        registerForActivityResult(
+            CreateDocument("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+        ) { uri ->
+            if (uri != null) {
+                repository.listTransactions.observe(viewLifecycleOwner) { list ->
+                    Log.d(this::class.java.simpleName, "Saving transactions to $uri")
+                    requireContext().contentResolver.openOutputStream(uri)?.use { fos ->
+                        createExcelFile(list, fos)
+                    }
+                }
+            }
+        }
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
@@ -25,8 +74,10 @@ class SettingsFragment : Fragment() {
     ): View {
         _binding = FragmentSettingsBinding.inflate(inflater, container, false)
 
+        val sessionManager = SessionManager(requireContext())
+
         binding.apply {
-            logoutButton.setOnClickListener {
+            buttonLogout.setOnClickListener {
                 val alertBuilder = AlertDialog.Builder(requireContext())
                 alertBuilder.setTitle(R.string.title_alert_logout)
                 alertBuilder.setMessage(R.string.message_alert_logout)
@@ -39,6 +90,59 @@ class SettingsFragment : Fragment() {
                 }
                 alertBuilder.show()
             }
+
+            ArrayAdapter.createFromResource(
+                requireContext(),
+                R.array.excel_types,
+                android.R.layout.simple_spinner_dropdown_item
+            ).also { arrayAdapter ->
+                arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+                spinnerExcelType.adapter = arrayAdapter
+            }
+
+            buttonSave.setOnClickListener {
+                when (spinnerExcelType.selectedItem.toString()) {
+                    "XLS" -> saveXls.launch("transactions.xls")
+                    "XLSX" -> saveXlsx.launch("transactions.xlsx")
+                }
+                Toast.makeText(requireContext(), R.string.transactions_saved, Toast.LENGTH_SHORT)
+                    .show()
+            }
+
+            buttonSendEmail.setOnClickListener {
+                sessionManager.ensureAuthenticated()
+                val token = sessionManager.fetchAuthToken()!!
+                val intent = Intent(Intent.ACTION_SEND).apply {
+                    type = "text/html"
+                    putExtra(Intent.EXTRA_EMAIL, arrayOf("${token.nim}@std.stei.itb.ac.id"))
+                    putExtra(Intent.EXTRA_SUBJECT, "Daftar Transaksi Aplikasi Bondoman")
+                    putExtra(
+                        Intent.EXTRA_TEXT,
+                        "Halo ${token.nim}, berikut daftar transaksi yang telah kamu catat dalam aplikasi Bondoman"
+                    )
+                    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                    val tempFile = File(requireContext().cacheDir, "transactions.xlsx")
+                    if (tempFile.exists()) {
+                        tempFile.delete()
+                    } else {
+                        tempFile.parentFile?.mkdirs()
+                    }
+                    val fileUri = FileProvider.getUriForFile(
+                        requireContext(),
+                        "${requireContext().packageName}.fileprovider",
+                        tempFile
+                    )
+                    repository.listTransactions.observe(viewLifecycleOwner) { list ->
+                        requireContext().contentResolver.openOutputStream(fileUri)?.use { fos ->
+                            createExcelFile(list, fos)
+                        }
+                    }
+                    putExtra(Intent.EXTRA_STREAM, fileUri)
+                }
+                startActivity(Intent.createChooser(intent, "Send email"))
+                Toast.makeText(requireContext(), R.string.transactions_sent, Toast.LENGTH_SHORT)
+                    .show()
+            }
         }
 
         return binding.root
@@ -56,4 +160,53 @@ class SettingsFragment : Fragment() {
         findNavController().popBackStack(R.id.navigation_transaction, true)
         requireActivity().recreate()
     }
+
+    private fun createExcelFile(data: List<TransactionEntity>, outputStream: OutputStream) {
+        workbook {
+            val headers = arrayOf(
+                "Tanggal",
+                "Kategori Transaksi",
+                "Nominal Transaksi",
+                "Nama Transaksi",
+                "Lokasi"
+            )
+            val sheet = sheet {
+                val headingStyle = createCellStyle {
+                    val font = createFont { bold = true }
+                    setFont(font)
+                    fillPattern = FillPatternType.SOLID_FOREGROUND
+                    fillForegroundColor = IndexedColors.AQUA.index
+                }
+                row(headingStyle) {
+                    headers.forEach { cell(it) }
+                }
+                for (transaction in data) {
+                    row {
+                        val date = transaction.date
+                            .toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDateTime()
+                            .format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"))
+                        cell(date)
+                        cell(transaction.category.text())
+                        cell(transaction.amount)
+                        cell(transaction.title)
+                        cell(transaction.location)
+                    }
+                }
+            }.xssfSheet
+            for (i in 0..headers.size) {
+                sheet.setColumnWidth(i, 30 * 256)
+            }
+        }.xssfWorkbook.write(outputStream)
+    }
+
+    private fun TransactionCategory.text(): String {
+        return when (this) {
+            TransactionCategory.INCOME -> "Pemasukan"
+            TransactionCategory.OUTCOME -> "Pengeluaran"
+            TransactionCategory.UNKNOWN -> ""
+        }
+
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt
index d43791d0f9b611492d3e60d466a0a93a6fe3c877..4ff1ccc32f50abe95a0e0e74e85e2595bf8997e6 100644
--- a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt
@@ -1,12 +1,16 @@
 package com.onionsquad.bondoman.ui.transaction
 
+import android.content.Intent
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
+import com.onionsquad.bondoman.AddTransactionActivity
 import com.onionsquad.bondoman.databinding.FragmentTransactionBinding
+import com.onionsquad.bondoman.repository.TransactionRepository
+import com.onionsquad.bondoman.room.TransactionDatabase
 
 class TransactionFragment : Fragment() {
 
@@ -16,16 +20,24 @@ class TransactionFragment : Fragment() {
     // onDestroyView.
     private val binding get() = _binding!!
 
+    private val database by lazy { TransactionDatabase.getInstance(requireContext().applicationContext) }
+    private val repository by lazy { TransactionRepository(database.transactionDao()) }
+
     override fun onCreateView(
             inflater: LayoutInflater,
             container: ViewGroup?,
             savedInstanceState: Bundle?
     ): View {
-        val transactionViewModel =
-                ViewModelProvider(this).get(TransactionViewModel::class.java)
+        val factory = TransactionViewModelFactory(repository)
+        val transactionViewModel = ViewModelProvider(this, factory)[TransactionViewModel::class.java]
 
         _binding = FragmentTransactionBinding.inflate(inflater, container, false)
 
+        binding.button.setOnClickListener {
+            val intent = Intent(activity, AddTransactionActivity::class.java)
+            startActivity(intent)
+        }
+
         return binding.root
     }
 
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt
index bb883eaad8241e46f1cb31cf707403419df2b22b..cf96283f3289be47bfd3205f7e6faa0ac4467748 100644
--- a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt
@@ -1,13 +1,24 @@
 package com.onionsquad.bondoman.ui.transaction
 
 import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.onionsquad.bondoman.repository.TransactionRepository
+import com.onionsquad.bondoman.room.TransactionEntity
+import kotlinx.coroutines.launch
 
-class TransactionViewModel : ViewModel() {
+class TransactionViewModel(private val repository : TransactionRepository) : ViewModel() {
+    var listTransactions: LiveData<List<TransactionEntity>> = repository.listTransactions
 
-    private val _text = MutableLiveData<String>().apply {
-        value = "This is dashboard Fragment"
+    fun insertTransaction(transaction: TransactionEntity) = viewModelScope.launch {
+        repository.insertTransaction(transaction)
+    }
+
+    fun updateTransaction(transaction: TransactionEntity) = viewModelScope.launch {
+        repository.updateTransaction(transaction)
+    }
+
+    fun deleteTransaction(transaction: TransactionEntity) = viewModelScope.launch {
+        repository.deleteTransaction(transaction)
     }
-    val text: LiveData<String> = _text
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModelFactory.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModelFactory.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d318bade3a0a3dfa99c25021f0e02aac38ab04c7
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModelFactory.kt
@@ -0,0 +1,17 @@
+package com.onionsquad.bondoman.ui.transaction
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.onionsquad.bondoman.repository.TransactionRepository
+
+class TransactionViewModelFactory(private val repository: TransactionRepository) :
+    ViewModelProvider.Factory {
+
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(TransactionViewModel::class.java)) {
+            @Suppress("UNCHECKED_CAST")
+            return TransactionViewModel(repository) as T
+        }
+        throw IllegalArgumentException("Unknown ViewModel class")
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/util/Converters.kt b/app/src/main/java/com/onionsquad/bondoman/util/Converters.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ce6beddb309958907a9a4f30e9e9f53511b04ac0
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/util/Converters.kt
@@ -0,0 +1,34 @@
+package com.onionsquad.bondoman.util
+
+import androidx.room.TypeConverter
+import com.onionsquad.bondoman.room.TransactionCategory
+import java.util.Date
+
+object Converters {
+
+    @TypeConverter
+    @JvmStatic
+    fun fromTimestamp(value: Long?): Date? {
+        return value?.let { Date(it) }
+    }
+
+    @TypeConverter
+    @JvmStatic
+    fun dateToTimestamp(value: Date?): Long? {
+        return value?.time
+    }
+
+    @TypeConverter
+    fun fromTransactionCategory(category: TransactionCategory): String {
+        return category.name
+    }
+
+    @TypeConverter
+    fun toTransactionCategory(categoryString: String): TransactionCategory {
+        return try {
+            TransactionCategory.valueOf(categoryString)
+        } catch (e: IllegalArgumentException) {
+            TransactionCategory.UNKNOWN
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_baseline_email_24.xml b/app/src/main/res/drawable/ic_baseline_email_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3335d40f9e0e89792c5336c7964bc79e145aa04
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_email_24.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+      
+    <path android:fillColor="@android:color/white" android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
+    
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_save_24.xml b/app/src/main/res/drawable/ic_baseline_save_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cfd40f5f8e0996658b48908b447dc9886b8ec601
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_save_24.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+      
+    <path android:fillColor="@android:color/white" android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
+    
+</vector>
diff --git a/app/src/main/res/layout/activity_add_transaction.xml b/app/src/main/res/layout/activity_add_transaction.xml
new file mode 100644
index 0000000000000000000000000000000000000000..95fa2b3af87c278d7b251600cecf1c1b0d0ddacb
--- /dev/null
+++ b/app/src/main/res/layout/activity_add_transaction.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Transaksi"
+        android:textSize="24sp"
+        android:textStyle="bold" />
+
+    <EditText
+        android:id="@+id/titleEditText"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:hint="Judul"
+        android:inputType="text" />
+
+    <EditText
+        android:id="@+id/amountEditText"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:hint="Nominal"
+        android:inputType="numberDecimal" />
+
+    <RadioGroup
+        android:id="@+id/categoryRadioGroup"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:orientation="horizontal">
+
+        <RadioButton
+            android:id="@+id/incomeRadioButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Pemasukan" />
+
+        <RadioButton
+            android:id="@+id/outcomeRadioButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Pengeluaran" />
+
+    </RadioGroup>
+
+    <EditText
+        android:id="@+id/locationEditText"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:hint="Lokasi"
+        android:inputType="text" />
+
+    <Button
+        android:id="@+id/saveButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:text="Simpan" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 570a31e7a5eb1be342b0845e3542c86cfe97a81c..b4fa8f9139a6487708df28d49918d4d29402779e 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -1,18 +1,53 @@
 <?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:orientation="vertical"
     tools:context=".ui.settings.SettingsFragment">
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/button_save"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.7"
+            android:backgroundTint="@color/white"
+            android:drawableLeft="@drawable/ic_baseline_save_24"
+            android:text="@string/action_save_transactions"
+            android:textAlignment="textStart"
+            android:textColor="@color/black" />
+
+        <Spinner
+            android:id="@+id/spinner_excel_type"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="0.3" />
+    </LinearLayout>
+
     <Button
-        android:id="@+id/logout_button"
+        android:id="@+id/button_send_email"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:backgroundTint="@color/white"
+        android:drawableLeft="@drawable/ic_baseline_email_24"
+        android:text="@string/action_save_email"
         android:textAlignment="textStart"
-        android:textColor="@color/design_default_color_error"
+        android:textColor="@color/black" />
+
+    <Button
+        android:id="@+id/button_logout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
         android:backgroundTint="@color/white"
         android:drawableLeft="@drawable/ic_baseline_logout_24"
         android:drawableTint="@color/design_default_color_error"
-        android:text="@string/action_sign_out" />
-</FrameLayout>
\ No newline at end of file
+        android:text="@string/action_sign_out"
+        android:textAlignment="textStart"
+        android:textColor="@color/design_default_color_error" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_transaction.xml b/app/src/main/res/layout/fragment_transaction.xml
index 57a856060acfaabd0a791420812b73e086ff07f7..26af3dd3316b3d39d8d4a93547724bcb95a87311 100644
--- a/app/src/main/res/layout/fragment_transaction.xml
+++ b/app/src/main/res/layout/fragment_transaction.xml
@@ -4,4 +4,17 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.transaction.TransactionFragment"/>
\ No newline at end of file
+    tools:context=".ui.transaction.TransactionFragment">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button"
+        android:visibility="visible"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000000000000000000000000000000000000..df459588e60132333d50587f1090784e62693410
--- /dev/null
+++ b/app/src/main/res/values/arrays.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string-array name="excel_types">
+        <item>XLS</item>
+        <item>XLSX</item>
+    </string-array>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 311f02b1f84e12b270a1b2d85afadf307f9caa25..e48d9841a8bfd416ef39ac9460a98e07c6693f2b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,4 +18,8 @@
     <string name="log_out_success">Log out success</string>
     <string name="yes">Yes</string>
     <string name="no">No</string>
+    <string name="action_save_transactions">Save transaction</string>
+    <string name="action_save_email">Send transactions</string>
+    <string name="transactions_saved">Transactions saved</string>
+    <string name="transactions_sent">Transactions sent to email</string>
 </resources>
\ No newline at end of file
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0a9df4b573a6caf941e16d0eb5b2f8cee1ce5cea
--- /dev/null
+++ b/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,3 @@
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <cache-path name="cache" path="/" />
+</paths>
diff --git a/build.gradle.kts b/build.gradle.kts
index a0985efc88dec705956b74f5d6e9ac23c8daebb8..56ccaddfbd0ae102cf1b1f8b9a4ea0727d5445c6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,4 +2,5 @@
 plugins {
     alias(libs.plugins.androidApplication) apply false
     alias(libs.plugins.jetbrainsKotlinAndroid) apply false
+    alias(libs.plugins.jetbrainsKotlinKapt) apply false
 }
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 20e2a01520742aff4ec9ce578ed4fe5f3a76fe77..68c91aec313598d3039f3466d1eca131beb5f553 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,6 +15,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
 # Android operating system, and which are packaged with your app's APK
 # https://developer.android.com/topic/libraries/support-library/androidx-rn
 android.useAndroidX=true
+android.enableJetifier=true
 # Kotlin code style for this project: "official" or "obsolete":
 kotlin.code.style=official
 # Enables namespacing of each library's R class so that its R class includes only the
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f97c4635183e36d7327b23cd0961282b2fec0b66..5dc08ee6ecbd46cc587d471484264b8f9153a6c0 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,6 +1,6 @@
 [versions]
-agp = "8.3.1"
-kotlin = "1.9.0"
+agp = "8.2.2"
+kotlin = "1.9.23"
 coreKtx = "1.10.1"
 junit = "4.13.2"
 junitVersion = "1.1.5"
@@ -12,10 +12,14 @@ lifecycleLivedataKtx = "2.6.1"
 lifecycleViewmodelKtx = "2.6.1"
 navigationFragmentKtx = "2.6.0"
 navigationUiKtx = "2.6.0"
+room = "2.6.1"
+kapt = "1.9.23"
+lifecycleViewmodelCompose = "2.7.0"
 retrofit = "2.11.0"
 okhttp3 = "4.12.0"
 annotation = "1.7.1"
 work = "2.9.0"
+excelkt = "1.0.2"
 
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -29,14 +33,21 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy
 androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
 androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
 androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
+room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
+room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
+room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
+room-common = { group = "androidx.room", name = "room-common", version.ref = "room" }
+androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
 retrofit2-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
 retrofit2-converter-scalars = { group = "com.squareup.retrofit2", name = "converter-scalars", version.ref = "retrofit" }
 retrofit2-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
 okhttp3 = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp3"  }
 androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" }
 androidx-work-runtime = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work" }
+excelkt = { group = "io.github.evanrupert", name = "excelkt", version.ref = "excelkt" }
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }
 jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+jetbrainsKotlinKapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kapt" }