loan order details more beautiful
This commit is contained in:
6
.cursor/rules/api.mdc
Normal file
6
.cursor/rules/api.mdc
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
All api are located inside resources openapi.json
|
||||
0
CHANGELOG.md
Normal file
0
CHANGELOG.md
Normal file
@@ -278,6 +278,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/alerts-all": {
|
||||
"get": {
|
||||
"operationId": "alert.all",
|
||||
"summary": "All alerts",
|
||||
"tags": [
|
||||
"Alert"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/components/responses/AuthenticationException"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/register": {
|
||||
"post": {
|
||||
"operationId": "apiAuth.register",
|
||||
@@ -387,12 +411,24 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"$ref": "#/components/schemas/ProfileResponse"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message"
|
||||
"success",
|
||||
"token",
|
||||
"message",
|
||||
"user"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -479,6 +515,69 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/contact-us": {
|
||||
"post": {
|
||||
"operationId": "contactUs.store",
|
||||
"summary": "Store contact us message",
|
||||
"tags": [
|
||||
"ContactUs"
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Message Title",
|
||||
"example": "Salam",
|
||||
"maxLength": 255
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Message content",
|
||||
"example": "Bet app",
|
||||
"maxLength": 255
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"message"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/components/responses/AuthenticationException"
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#/components/responses/ValidationException"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/metrics": {
|
||||
"get": {
|
||||
"operationId": "metrics.index",
|
||||
@@ -528,31 +627,11 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"description": "`ProfileResponse`",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_serie": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"phone",
|
||||
"passport_serie",
|
||||
"passport_id"
|
||||
]
|
||||
"$ref": "#/components/schemas/ProfileResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2582,14 +2661,11 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Paginated set of `LoanOrderIndexResource`",
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LoanOrderIndexResource"
|
||||
}
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3474,6 +3550,22 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/visa-master-order": {
|
||||
"get": {
|
||||
"operationId": "visaMasterPaymentOrder.index",
|
||||
"tags": [
|
||||
"VisaMasterPaymentOrder"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/components/responses/AuthenticationException"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@@ -5155,391 +5247,6 @@
|
||||
],
|
||||
"title": "CardTransaction"
|
||||
},
|
||||
"LoanOrderIndexResource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"unique_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"loan_type": {
|
||||
"type": "integer"
|
||||
},
|
||||
"region": {
|
||||
"type": "string"
|
||||
},
|
||||
"branch_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"customer_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_surname": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_patronic_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"passport_address": {
|
||||
"type": "string"
|
||||
},
|
||||
"real_address": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_serie": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_given_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"passport_given_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"born_place": {
|
||||
"type": "string"
|
||||
},
|
||||
"born_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"email": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone_additional": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"phone_home": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_region": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_province_id": {
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_company": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_company_accountant_number": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_started_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time"
|
||||
},
|
||||
"work_salary": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"work_position": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"education": {
|
||||
"type": "string"
|
||||
},
|
||||
"marriage_status": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_one": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_two": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_three": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_four": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_id": {
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"created_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time"
|
||||
},
|
||||
"deleted_at": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time"
|
||||
},
|
||||
"loan_amount": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_surname": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_patronic_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_card_number": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_card_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_card_month": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_card_year": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_surname": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_patronic_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_card_number": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_card_name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_card_month": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_card_year": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mobile"
|
||||
]
|
||||
},
|
||||
"guarantor_note": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_note": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"satisfiable": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_passport_serie": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_passport_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_passport_serie": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"guarantor_2_passport_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"unique_id",
|
||||
"loan_type",
|
||||
"region",
|
||||
"branch_id",
|
||||
"customer_name",
|
||||
"customer_surname",
|
||||
"customer_patronic_name",
|
||||
"passport_address",
|
||||
"real_address",
|
||||
"passport_serie",
|
||||
"passport_id",
|
||||
"passport_given_at",
|
||||
"passport_given_by",
|
||||
"born_place",
|
||||
"born_at",
|
||||
"email",
|
||||
"phone",
|
||||
"phone_additional",
|
||||
"phone_home",
|
||||
"work_region",
|
||||
"work_province_id",
|
||||
"work_company",
|
||||
"work_company_accountant_number",
|
||||
"work_started_at",
|
||||
"work_salary",
|
||||
"work_position",
|
||||
"education",
|
||||
"marriage_status",
|
||||
"passport_one",
|
||||
"passport_two",
|
||||
"passport_three",
|
||||
"passport_four",
|
||||
"user_id",
|
||||
"status",
|
||||
"notes",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"loan_amount",
|
||||
"guarantor_name",
|
||||
"guarantor_surname",
|
||||
"guarantor_patronic_name",
|
||||
"guarantor_card_number",
|
||||
"guarantor_card_name",
|
||||
"guarantor_card_month",
|
||||
"guarantor_card_year",
|
||||
"guarantor_2_name",
|
||||
"guarantor_2_surname",
|
||||
"guarantor_2_patronic_name",
|
||||
"guarantor_2_card_number",
|
||||
"guarantor_2_card_name",
|
||||
"guarantor_2_card_month",
|
||||
"guarantor_2_card_year",
|
||||
"source",
|
||||
"guarantor_note",
|
||||
"guarantor_2_note",
|
||||
"satisfiable",
|
||||
"guarantor_passport_serie",
|
||||
"guarantor_passport_id",
|
||||
"guarantor_2_passport_serie",
|
||||
"guarantor_2_passport_id"
|
||||
],
|
||||
"title": "LoanOrderIndexResource"
|
||||
},
|
||||
"LoanOrderShowResource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6196,7 +5903,10 @@
|
||||
"maxLength": 255
|
||||
},
|
||||
"guarantor_patronic_name": {
|
||||
"type": "string",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Guarantor surname",
|
||||
"example": "Owezowic",
|
||||
"maxLength": 255
|
||||
@@ -6346,7 +6056,6 @@
|
||||
"passport_four",
|
||||
"guarantor_name",
|
||||
"guarantor_surname",
|
||||
"guarantor_patronic_name",
|
||||
"guarantor_card_number",
|
||||
"guarantor_card_name",
|
||||
"guarantor_card_month",
|
||||
@@ -7060,6 +6769,45 @@
|
||||
],
|
||||
"title": "LoanRemainingOrder"
|
||||
},
|
||||
"ProfileResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"passport_serie": {
|
||||
"type": "string"
|
||||
},
|
||||
"passport_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"card_number": {
|
||||
"type": "string"
|
||||
},
|
||||
"card_month": {
|
||||
"type": "string"
|
||||
},
|
||||
"card_year": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"phone",
|
||||
"passport_serie",
|
||||
"passport_id",
|
||||
"card_number",
|
||||
"card_month",
|
||||
"card_year"
|
||||
],
|
||||
"title": "ProfileResponse"
|
||||
},
|
||||
"UpdateUserProfileRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7083,10 +6831,7 @@
|
||||
"example": "MyFcpassword"
|
||||
},
|
||||
"passport_serie": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Passport serie",
|
||||
"enum": [
|
||||
"I-AS",
|
||||
@@ -7104,12 +6849,104 @@
|
||||
"example": "I-AS"
|
||||
},
|
||||
"passport_id": {
|
||||
"type": [
|
||||
"number",
|
||||
"null"
|
||||
],
|
||||
"type": "number",
|
||||
"description": "Passport id",
|
||||
"example": 100999
|
||||
},
|
||||
"card_number": {
|
||||
"type": "string",
|
||||
"example": "9934612100000543"
|
||||
},
|
||||
"card_month": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"01",
|
||||
"02",
|
||||
"03",
|
||||
"04",
|
||||
"05",
|
||||
"06",
|
||||
"07",
|
||||
"08",
|
||||
"09",
|
||||
"10",
|
||||
"11",
|
||||
"12"
|
||||
],
|
||||
"example": "12"
|
||||
},
|
||||
"card_year": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"2024",
|
||||
"2025",
|
||||
"2026",
|
||||
"2027",
|
||||
"2028",
|
||||
"2029",
|
||||
"2030",
|
||||
"2031",
|
||||
"2032",
|
||||
"2033",
|
||||
"2034",
|
||||
"2035",
|
||||
"2036",
|
||||
"2037",
|
||||
"2038",
|
||||
"2039",
|
||||
"2040",
|
||||
"2041",
|
||||
"2042",
|
||||
"2043",
|
||||
"2044",
|
||||
"2045",
|
||||
"2046",
|
||||
"2047",
|
||||
"2048",
|
||||
"2049",
|
||||
"2050",
|
||||
"2051",
|
||||
"2052",
|
||||
"2053",
|
||||
"2054",
|
||||
"2055",
|
||||
"2056",
|
||||
"2057",
|
||||
"2058",
|
||||
"2059",
|
||||
"2060",
|
||||
"2061",
|
||||
"2062",
|
||||
"2063",
|
||||
"2064",
|
||||
"2065",
|
||||
"2066",
|
||||
"2067",
|
||||
"2068",
|
||||
"2069",
|
||||
"2070",
|
||||
"2071",
|
||||
"2072",
|
||||
"2073",
|
||||
"2074",
|
||||
"2075",
|
||||
"2076",
|
||||
"2077",
|
||||
"2078",
|
||||
"2079",
|
||||
"2080",
|
||||
"2081",
|
||||
"2082",
|
||||
"2083",
|
||||
"2084",
|
||||
"2085",
|
||||
"2086",
|
||||
"2087",
|
||||
"2088",
|
||||
"2089",
|
||||
"2090"
|
||||
],
|
||||
"example": "2049"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
0
roadmap.md
Normal file
0
roadmap.md
Normal file
@@ -9,6 +9,9 @@ import LoanPaidOffLetterOrderDetailsScreen from '../screens/Loan/LoanPaidOffLett
|
||||
import LoanOrdersScreen from '../screens/Loan/LoanOrdersScreen';
|
||||
import CreateLoanOrderScreen from '../screens/Loan/CreateLoanOrderScreen';
|
||||
import LoanOrderDetailsScreen from '../screens/Loan/LoanOrderDetailsScreen';
|
||||
import CardTransactionOrdersScreen from '../screens/Card/CardTransactionOrdersScreen';
|
||||
import CreateCardTransactionOrderScreen from '../screens/Card/CreateCardTransactionOrderScreen';
|
||||
import CardTransactionOrderDetailsScreen from '../screens/Card/CardTransactionOrderDetailsScreen';
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
@@ -23,6 +26,9 @@ const MenuNavigator = () => (
|
||||
<Stack.Screen name="LoanOrders" component={LoanOrdersScreen} />
|
||||
<Stack.Screen name="CreateLoanOrder" component={CreateLoanOrderScreen} />
|
||||
<Stack.Screen name="LoanOrderDetails" component={LoanOrderDetailsScreen} />
|
||||
<Stack.Screen name="CardTransactionOrders" component={CardTransactionOrdersScreen} />
|
||||
<Stack.Screen name="CreateCardTransactionOrder" component={CreateCardTransactionOrderScreen} />
|
||||
<Stack.Screen name="CardTransactionOrderDetails" component={CardTransactionOrderDetailsScreen} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
|
||||
|
||||
253
src/screens/Card/CardTransactionOrderDetailsScreen.js
Normal file
253
src/screens/Card/CardTransactionOrderDetailsScreen.js
Normal file
@@ -0,0 +1,253 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert, ScrollView, SafeAreaView, Modal } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import apiService from '../../services/apiService';
|
||||
import { COLORS } from '../../constants/colors';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import DateInput from '../../components/DateInput';
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
const DetailRow = ({ label, value, showBorder = true }) => (
|
||||
<View style={[styles.detailRow, showBorder && styles.detailRowBorder]}>
|
||||
<Text style={styles.detailKey}>{label}</Text>
|
||||
<Text style={styles.detailValue}>{String(value)}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const CardTransactionOrderDetailsScreen = () => {
|
||||
const navigation = useNavigation();
|
||||
const route = useRoute();
|
||||
const { orderId } = route.params || {};
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [order, setOrder] = useState(null);
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [startDate, setStartDate] = useState('');
|
||||
const [endDate, setEndDate] = useState('');
|
||||
const [downloading, setDownloading] = useState(false);
|
||||
|
||||
const fetchDetails = async () => {
|
||||
setLoading(true);
|
||||
const res = await apiService.getCardTransactionOrder(orderId);
|
||||
if (res.success) {
|
||||
setOrder(res.data);
|
||||
} else {
|
||||
Alert.alert('Error', res.error || 'Could not fetch details');
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchDetails();
|
||||
}, []);
|
||||
|
||||
const handleDelete = () => {
|
||||
Alert.alert('Confirm', 'Are you sure you want to delete this order?', [
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{ text: 'Delete', style: 'destructive', onPress: deleteOrder },
|
||||
]);
|
||||
};
|
||||
|
||||
const deleteOrder = async () => {
|
||||
const res = await apiService.deleteCardTransactionOrder(orderId);
|
||||
if (res.success) {
|
||||
Alert.alert('Deleted', res.message || 'Order deleted', [
|
||||
{ text: 'OK', onPress: () => navigation.goBack() },
|
||||
]);
|
||||
} else {
|
||||
Alert.alert('Error', res.error || 'Could not delete');
|
||||
}
|
||||
};
|
||||
|
||||
const openDownloadModal = () => {
|
||||
setStartDate('');
|
||||
setEndDate('');
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (!startDate || !endDate) {
|
||||
Alert.alert('Error', 'Select both dates');
|
||||
return;
|
||||
}
|
||||
setDownloading(true);
|
||||
const res = await apiService.downloadCardTransactions(orderId, startDate, endDate);
|
||||
setDownloading(false);
|
||||
if (res.success && res.data?.url) {
|
||||
Linking.openURL(res.data.url);
|
||||
setModalVisible(false);
|
||||
} else {
|
||||
Alert.alert('Error', res.error || 'Could not download');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={styles.centered}>
|
||||
<ActivityIndicator size="large" color={COLORS.primary} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!order) {
|
||||
return (
|
||||
<View style={styles.centered}>
|
||||
<Text>No data</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar style="dark" />
|
||||
<TouchableOpacity style={styles.backBtn} onPress={() => navigation.goBack()}>
|
||||
<Ionicons name="close" size={28} color={COLORS.textPrimary} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 40, paddingHorizontal: 24 }}>
|
||||
<Text style={styles.title}>Kart hereketleri</Text>
|
||||
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="ID" value={order.id} />
|
||||
{order.card_number && <DetailRow label="Kart" value={order.card_number} />}
|
||||
{order.card_month && order.card_year && <DetailRow label="Kartyň möhleti" value={`${order.card_month}/${order.card_year}`} />}
|
||||
{order.passport_serie && order.passport_id && <DetailRow label="Pasport" value={`${order.passport_serie} ${order.passport_id}`} />}
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.actionBtn} onPress={openDownloadModal}>
|
||||
<Text style={styles.actionText}>Ýükle (PDF)</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.deleteBtn} onPress={handleDelete}>
|
||||
<Text style={styles.deleteText}>Poz</Text>
|
||||
</TouchableOpacity>
|
||||
</ScrollView>
|
||||
|
||||
{/* Download modal */}
|
||||
<Modal visible={modalVisible} transparent animationType="fade" onRequestClose={() => setModalVisible(false)}>
|
||||
<View style={styles.modalBackdrop}>
|
||||
<View style={styles.modalCard}>
|
||||
<Text style={styles.modalTitle}>Sene aralygy</Text>
|
||||
<DateInput label="*Başla" value={startDate} onChange={setStartDate} />
|
||||
<DateInput label="*Tamamla" value={endDate} onChange={setEndDate} />
|
||||
|
||||
<TouchableOpacity style={styles.submitBtn} onPress={handleDownload} disabled={downloading}>
|
||||
{downloading ? (
|
||||
<ActivityIndicator color={COLORS.white} />
|
||||
) : (
|
||||
<Text style={styles.submitText}>Ýükle</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={() => setModalVisible(false)} style={{ marginTop: 16, alignItems: 'center' }}>
|
||||
<Text style={{ color: COLORS.error }}>Ýap</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: COLORS.backgroundSecondary,
|
||||
paddingTop: 40,
|
||||
},
|
||||
centered: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
backBtn: {
|
||||
alignSelf: 'flex-end',
|
||||
marginRight: 24,
|
||||
marginBottom: 16,
|
||||
},
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 24,
|
||||
},
|
||||
detailCard: {
|
||||
backgroundColor: COLORS.white,
|
||||
borderRadius: 12,
|
||||
padding: 20,
|
||||
marginBottom: 32,
|
||||
},
|
||||
detailRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: 12,
|
||||
},
|
||||
detailRowBorder: {
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: COLORS.border,
|
||||
},
|
||||
detailKey: {
|
||||
fontWeight: '600',
|
||||
color: COLORS.textSecondary,
|
||||
},
|
||||
detailValue: {
|
||||
color: COLORS.textPrimary,
|
||||
},
|
||||
actionBtn: {
|
||||
backgroundColor: COLORS.primary,
|
||||
paddingVertical: 16,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
actionText: {
|
||||
color: COLORS.white,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
deleteBtn: {
|
||||
backgroundColor: COLORS.error,
|
||||
paddingVertical: 16,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
deleteText: {
|
||||
color: COLORS.white,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
modalBackdrop: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.25)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
modalCard: {
|
||||
backgroundColor: COLORS.white,
|
||||
borderRadius: 12,
|
||||
width: '100%',
|
||||
padding: 24,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 16,
|
||||
},
|
||||
submitBtn: {
|
||||
marginTop: 8,
|
||||
backgroundColor: COLORS.primary,
|
||||
paddingVertical: 14,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
submitText: {
|
||||
color: COLORS.white,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
||||
export default CardTransactionOrderDetailsScreen;
|
||||
190
src/screens/Card/CardTransactionOrdersScreen.js
Normal file
190
src/screens/Card/CardTransactionOrdersScreen.js
Normal file
@@ -0,0 +1,190 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text, StyleSheet, FlatList, ActivityIndicator, TouchableOpacity, RefreshControl, SafeAreaView } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useNavigation, useFocusEffect } from '@react-navigation/native';
|
||||
import apiService from '../../services/apiService';
|
||||
import { COLORS } from '../../constants/colors';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
|
||||
const CARD_BG = '#F1F9F1';
|
||||
const CIRCLE_BG = '#A2E4A4';
|
||||
|
||||
const CardTransactionOrdersScreen = () => {
|
||||
const navigation = useNavigation();
|
||||
const [orders, setOrders] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const fetchOrders = async () => {
|
||||
try {
|
||||
const res = await apiService.getCardTransactionOrders();
|
||||
if (res.success) {
|
||||
setOrders(Array.isArray(res.data) ? res.data : []);
|
||||
} else {
|
||||
console.warn(res.error);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setRefreshing(false);
|
||||
}
|
||||
};
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
fetchOrders();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onRefresh = () => {
|
||||
setRefreshing(true);
|
||||
fetchOrders();
|
||||
};
|
||||
|
||||
const handleItemPress = (item) => {
|
||||
navigation.navigate('CardTransactionOrderDetails', { orderId: item.id });
|
||||
};
|
||||
|
||||
const renderItem = ({ item }) => {
|
||||
const cardNum = item.card_number || '';
|
||||
const masked = cardNum ? `${cardNum.slice(0, 6)}******${cardNum.slice(-4)}` : '';
|
||||
const created = item.created_at ? new Date(item.created_at).toLocaleDateString() : '';
|
||||
const passportLine = item.passport_serie && item.passport_id ? `Pasport: ${item.passport_serie} ${item.passport_id}` : '';
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.card} onPress={() => handleItemPress(item)}>
|
||||
<View style={styles.circle}>
|
||||
<Text style={styles.circleText}>{item.id}</Text>
|
||||
</View>
|
||||
<View style={styles.cardContent}>
|
||||
<Text style={styles.cardNumber}>{masked}</Text>
|
||||
{passportLine !== '' && <Text style={styles.passportText}>{passportLine}</Text>}
|
||||
<Text style={styles.dateText}>{created}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={styles.centered}>
|
||||
<ActivityIndicator size="large" color={COLORS.primary} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar style="dark" />
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={{ paddingRight: 12 }}>
|
||||
<Ionicons name="arrow-back" size={24} color={COLORS.textPrimary} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Kart hereketleri</Text>
|
||||
</View>
|
||||
<FlatList
|
||||
data={orders}
|
||||
keyExtractor={(item) => item.id?.toString()}
|
||||
renderItem={renderItem}
|
||||
contentContainerStyle={orders.length === 0 && styles.emptyContainer}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||
ListEmptyComponent={<Text style={styles.emptyText}>No orders yet</Text>}
|
||||
/>
|
||||
|
||||
{/* Floating Action Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.fab}
|
||||
onPress={() => navigation.navigate('CreateCardTransactionOrder')}
|
||||
>
|
||||
<Ionicons name="add" size={28} color={COLORS.white} />
|
||||
</TouchableOpacity>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: COLORS.backgroundSecondary,
|
||||
},
|
||||
centered: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
color: COLORS.textPrimary,
|
||||
},
|
||||
card: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: CARD_BG,
|
||||
marginHorizontal: 24,
|
||||
marginTop: 16,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
},
|
||||
circle: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: CIRCLE_BG,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 16,
|
||||
},
|
||||
circleText: {
|
||||
color: COLORS.white,
|
||||
fontWeight: '600',
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1,
|
||||
},
|
||||
cardNumber: {
|
||||
fontWeight: '700',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 4,
|
||||
},
|
||||
dateText: {
|
||||
color: COLORS.textSecondary,
|
||||
fontSize: 12,
|
||||
},
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
emptyText: {
|
||||
fontSize: 16,
|
||||
color: COLORS.textSecondary,
|
||||
},
|
||||
fab: {
|
||||
position: 'absolute',
|
||||
bottom: 32,
|
||||
right: 32,
|
||||
backgroundColor: COLORS.primary,
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 28,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
elevation: 4,
|
||||
},
|
||||
passportText: {
|
||||
color: COLORS.textSecondary,
|
||||
fontSize: 14,
|
||||
marginBottom: 2,
|
||||
},
|
||||
});
|
||||
|
||||
export default CardTransactionOrdersScreen;
|
||||
150
src/screens/Card/CreateCardTransactionOrderScreen.js
Normal file
150
src/screens/Card/CreateCardTransactionOrderScreen.js
Normal file
@@ -0,0 +1,150 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, Alert, SafeAreaView, ScrollView } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import apiService from '../../services/apiService';
|
||||
import { COLORS } from '../../constants/colors';
|
||||
import Input from '../../components/Input';
|
||||
import SelectInput from '../../components/SelectInput';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { useAuth } from '../../contexts/AuthContext';
|
||||
|
||||
// Build options for months and years
|
||||
const monthOptions = Array.from({ length: 12 }).map((_, i) => {
|
||||
const m = String(i + 1).padStart(2, '0');
|
||||
return { label: m, value: m };
|
||||
});
|
||||
const yearOptions = Array.from({ length: 60 }).map((_, i) => {
|
||||
const y = String(new Date().getFullYear() + i);
|
||||
return { label: y, value: y };
|
||||
});
|
||||
|
||||
const PASSPORT_SERIES = ['I-AS','I-MR','II-MR','I-AH','II-AH','I-LB','II-LB','I-BN','II-BN','I-DZ','II-DZ'];
|
||||
|
||||
const CreateCardTransactionOrderScreen = () => {
|
||||
const navigation = useNavigation();
|
||||
const [cardNumber, setCardNumber] = useState('');
|
||||
const [cardMonth, setCardMonth] = useState('');
|
||||
const [cardYear, setCardYear] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { user } = useAuth();
|
||||
const [passportSerie, setPassportSerie] = useState('');
|
||||
const [passportId, setPassportId] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
if (user.passport_serie) setPassportSerie(user.passport_serie);
|
||||
if (user.passport_id) setPassportId(String(user.passport_id));
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!cardNumber.trim() || !cardMonth || !cardYear || !passportSerie || !passportId.trim()) {
|
||||
Alert.alert('Error', 'All fields are required');
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const res = await apiService.createCardTransactionOrder(cardNumber.trim(), cardMonth, cardYear, passportSerie, passportId.trim());
|
||||
setLoading(false);
|
||||
if (res.success) {
|
||||
Alert.alert('Success', res.message || 'Order created successfully', [
|
||||
{ text: 'OK', onPress: () => navigation.goBack() },
|
||||
]);
|
||||
} else {
|
||||
Alert.alert('Error', res.error || 'Could not create order');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar style="dark" />
|
||||
<ScrollView contentContainerStyle={{ paddingHorizontal: 24, paddingTop: 40, paddingBottom: 40 }}>
|
||||
<TouchableOpacity style={styles.backBtn} onPress={() => navigation.goBack()}>
|
||||
<Ionicons name="arrow-back" size={24} color={COLORS.textPrimary} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.title}>Täze sargyt</Text>
|
||||
|
||||
<SelectInput
|
||||
label="*Passport seriýasy"
|
||||
value={passportSerie}
|
||||
onValueChange={setPassportSerie}
|
||||
options={PASSPORT_SERIES.map((v) => ({ label: v, value: v }))}
|
||||
placeholder="Saýla"
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="*Passport belgisi"
|
||||
placeholder="123456"
|
||||
value={passportId}
|
||||
onChangeText={setPassportId}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="*Kart belgisi"
|
||||
placeholder="9934..."
|
||||
value={cardNumber}
|
||||
onChangeText={setCardNumber}
|
||||
keyboardType="numeric"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
label="*Aý"
|
||||
value={cardMonth}
|
||||
onValueChange={setCardMonth}
|
||||
options={monthOptions}
|
||||
placeholder="Saýla"
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
label="*Ýyl"
|
||||
value={cardYear}
|
||||
onValueChange={setCardYear}
|
||||
options={yearOptions}
|
||||
placeholder="Saýla"
|
||||
/>
|
||||
|
||||
<TouchableOpacity style={styles.submitBtn} onPress={handleSubmit} disabled={loading}>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={COLORS.white} />
|
||||
) : (
|
||||
<Text style={styles.submitText}>Ýatda sakla</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: COLORS.backgroundSecondary,
|
||||
},
|
||||
backBtn: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 24,
|
||||
},
|
||||
submitBtn: {
|
||||
marginTop: 32,
|
||||
backgroundColor: COLORS.primary,
|
||||
paddingVertical: 16,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
submitText: {
|
||||
color: COLORS.white,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
||||
export default CreateCardTransactionOrderScreen;
|
||||
@@ -6,14 +6,30 @@ import apiService from '../../services/apiService';
|
||||
import { COLORS } from '../../constants/colors';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
|
||||
const formatDate = (dstr) => {
|
||||
if (!dstr) return '-';
|
||||
const d = new Date(dstr);
|
||||
return isNaN(d) ? dstr : d.toLocaleDateString('tk-TM');
|
||||
// Helper formatters
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
if (isNaN(d)) return dateStr;
|
||||
return d.toLocaleDateString('tk-TM');
|
||||
};
|
||||
|
||||
const DetailRow = ({ label, value, last }) => (
|
||||
<View style={[styles.detailRow, !last && styles.detailRowBorder]}>
|
||||
const formatDateTime = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
if (isNaN(d)) return dateStr;
|
||||
return d.toLocaleString('tk-TM', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
});
|
||||
};
|
||||
|
||||
// Key/value row
|
||||
const DetailRow = ({ label, value, showBorder = true }) => (
|
||||
<View style={[styles.detailRow, showBorder && styles.detailRowBorder]}>
|
||||
<Text style={styles.detailKey}>{label}</Text>
|
||||
<Text style={styles.detailValue}>{String(value)}</Text>
|
||||
</View>
|
||||
@@ -76,6 +92,11 @@ const LoanOrderDetailsScreen = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Pre-computed helpers
|
||||
const fullName = `${order.customer_name ?? ''} ${order.customer_surname ?? ''} ${order.customer_patronic_name ?? ''}`.trim();
|
||||
const guarantorFullName = `${order.guarantor_name ?? ''} ${order.guarantor_surname ?? ''} ${order.guarantor_patronic_name ?? ''}`.trim();
|
||||
const guarantor2FullName = `${order.guarantor_2_name ?? ''} ${order.guarantor_2_surname ?? ''} ${order.guarantor_2_patronic_name ?? ''}`.trim();
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar style="dark" />
|
||||
@@ -83,31 +104,114 @@ const LoanOrderDetailsScreen = () => {
|
||||
<Ionicons name="close" size={28} color={COLORS.textPrimary} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 40, paddingHorizontal: 24 }}>
|
||||
<Text style={styles.title}>Karz sargyt maglumatlary</Text>
|
||||
{/* Ensure enough bottom padding so content is not hidden behind the tab bar */}
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 120, paddingRight: 16, paddingLeft: 16 }}>
|
||||
<Text style={styles.title}>Karz sargyt: {order.unique_id}</Text>
|
||||
|
||||
{/* Basic order info */}
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="ID" value={order.id} />
|
||||
<DetailRow label="Karz mukdary" value={order.loan_amount} />
|
||||
<DetailRow label="Loan type" value={order.loan_type} />
|
||||
<DetailRow label="Status" value={order.status ?? '-'} />
|
||||
<DetailRow label="Bellik" value={order.notes ?? '-'} last />
|
||||
{order.unique_id && <DetailRow label="ID" value={order.unique_id} />}
|
||||
{order.created_at && <DetailRow label="Döredilen wagty" value={formatDateTime(order.created_at)} />}
|
||||
{order.updated_at && <DetailRow label="Täzelenen wagty" value={formatDateTime(order.updated_at)} />}
|
||||
{order.status && <DetailRow label="Status" value={order.status} />}
|
||||
<DetailRow label="Bellik" value={order.notes ?? '-'} showBorder={false} />
|
||||
</View>
|
||||
|
||||
<Text style={styles.sectionTitle}>Müşderi</Text>
|
||||
{/* Loan details */}
|
||||
<Text style={styles.sectionTitle}>Karz barada maglumatlar</Text>
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="FIO" value={`${order.customer_name} ${order.customer_surname} ${order.customer_patronic_name ?? ''}`.trim()} />
|
||||
<DetailRow label="Doglan senesi" value={formatDate(order.born_at)} />
|
||||
<DetailRow label="Telefon" value={order.phone} />
|
||||
<DetailRow label="Passport" value={`${order.passport_serie} ${order.passport_id}`} last />
|
||||
{order.loan_amount && <DetailRow label="Karzyň möçberi" value={order.loan_amount} />}
|
||||
{order.loan_type && <DetailRow label="Karzyň görnüşi" value={order.loan_type} showBorder={order.satisfiable ? true : false} />}
|
||||
{order.satisfiable && <DetailRow label="Ýerine ýetirme ýagdaýy" value={order.satisfiable} showBorder={false} />}
|
||||
</View>
|
||||
|
||||
{/* Address */}
|
||||
<Text style={styles.sectionTitle}>Salgylary</Text>
|
||||
{/* Location */}
|
||||
{(order.region || order.branch) && (
|
||||
<>
|
||||
<Text style={styles.sectionTitle}>Lokasiýa</Text>
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="Passport salgysy" value={order.passport_address} />
|
||||
<DetailRow label="Real salgysy" value={order.real_address} last />
|
||||
{order.region && <DetailRow label="Welaýat" value={order.region} />}
|
||||
{order.branch && <DetailRow label="Şahamça" value={order.branch} showBorder={false} />}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Personal information */}
|
||||
<Text style={styles.sectionTitle}>Şahsy maglumatlar</Text>
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="Doly ady" value={fullName} />
|
||||
{order.born_at && <DetailRow label="Doglan güni" value={formatDate(order.born_at)} />}
|
||||
{order.born_place && <DetailRow label="Doglan ýeri" value={order.born_place} />}
|
||||
{order.marriage_status && <DetailRow label="Maşgala ýagdaýy" value={order.marriage_status} />}
|
||||
{order.education && <DetailRow label="Bilimi" value={order.education} />}
|
||||
{order.phone && <DetailRow label="Telefon" value={`+993 ${order.phone}`} />}
|
||||
{order.phone_additional && <DetailRow label="Goşmaça telefon" value={order.phone_additional} />}
|
||||
{order.phone_home && <DetailRow label="Öý telefon" value={order.phone_home} />}
|
||||
{order.email && <DetailRow label="E-poçta" value={order.email} />}
|
||||
{order.passport_serie && order.passport_id && <DetailRow label="Pasport" value={`${order.passport_serie} ${order.passport_id}`} />}
|
||||
{order.passport_given_at && <DetailRow label="Pasport berlen senesi" value={formatDate(order.passport_given_at)} />}
|
||||
{order.passport_given_by && <DetailRow label="Pasport beren gurama" value={order.passport_given_by} />}
|
||||
{order.passport_address && <DetailRow label="Ýaşaýan salgysy" value={order.passport_address} showBorder={false} />}
|
||||
</View>
|
||||
|
||||
{/* Work info */}
|
||||
{(order.work_company || order.work_position) && (
|
||||
<>
|
||||
<Text style={styles.sectionTitle}>Iş barada maglumatlar</Text>
|
||||
<View style={styles.detailCard}>
|
||||
{order.work_company && <DetailRow label="Işleýän ýeri" value={order.work_company} />}
|
||||
{order.work_position && <DetailRow label="Wezipesi" value={order.work_position} />}
|
||||
{order.work_salary && <DetailRow label="Zähmet haky" value={order.work_salary} />}
|
||||
{order.work_started_at && <DetailRow label="Işe başlan senesi" value={formatDate(order.work_started_at)} />}
|
||||
{order.work_company_accountant_number && <DetailRow label="Işgärler bölüminiň iş belgisi" value={order.work_company_accountant_number} />}
|
||||
{order.work_region && <DetailRow label="Iş ýeriniň etraby" value={order.work_region} />}
|
||||
{order.work_province && <DetailRow label="Iş ýeriniň welaýaty" value={order.work_province} showBorder={false} />}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Applicant card info */}
|
||||
{order.card_number && (
|
||||
<>
|
||||
<Text style={styles.sectionTitle}>Kartanyň maglumatlary (Arza beriji)</Text>
|
||||
<View style={styles.detailCard}>
|
||||
{order.card_name && <DetailRow label="Kartanyň ady" value={order.card_name} />}
|
||||
<DetailRow label="Kartanyň belgisi" value={order.card_number} />
|
||||
{order.card_month && <DetailRow label="Karta – aý" value={order.card_month} />}
|
||||
{order.card_year && <DetailRow label="Karta – ýyl" value={order.card_year} showBorder={false} />}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Guarantor 1 */}
|
||||
{guarantorFullName.trim() && (
|
||||
<>
|
||||
<Text style={styles.sectionTitle}>Zamun (1)</Text>
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="Doly ady" value={guarantorFullName} />
|
||||
{order.guarantor_card_name && <DetailRow label="Kartanyň ady" value={order.guarantor_card_name} />}
|
||||
{order.guarantor_card_number && <DetailRow label="Kartanyň belgisi" value={order.guarantor_card_number} />}
|
||||
{order.guarantor_card_month && <DetailRow label="Karta – aý" value={order.guarantor_card_month} />}
|
||||
{order.guarantor_card_year && <DetailRow label="Karta – ýyl" value={order.guarantor_card_year} />}
|
||||
{order.guarantor_note && <DetailRow label="Bellik" value={order.guarantor_note} showBorder={false} />}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Guarantor 2 */}
|
||||
{guarantor2FullName.trim() && (
|
||||
<>
|
||||
<Text style={styles.sectionTitle}>Zamun (2)</Text>
|
||||
<View style={styles.detailCard}>
|
||||
<DetailRow label="Doly ady" value={guarantor2FullName} />
|
||||
{order.guarantor_2_card_name && <DetailRow label="Kartanyň ady" value={order.guarantor_2_card_name} />}
|
||||
{order.guarantor_2_card_number && <DetailRow label="Kartanyň belgisi" value={order.guarantor_2_card_number} />}
|
||||
{order.guarantor_2_card_month && <DetailRow label="Karta – aý" value={order.guarantor_2_card_month} />}
|
||||
{order.guarantor_2_card_year && <DetailRow label="Karta – ýyl" value={order.guarantor_2_card_year} />}
|
||||
{order.guarantor_2_note && <DetailRow label="Bellik" value={order.guarantor_2_note} showBorder={false} />}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TouchableOpacity style={styles.deleteBtn} onPress={handleDelete}>
|
||||
<Text style={styles.deleteText}>Poz</Text>
|
||||
@@ -118,7 +222,12 @@ const LoanOrderDetailsScreen = () => {
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: COLORS.backgroundSecondary },
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: COLORS.backgroundSecondary,
|
||||
paddingHorizontal: 24,
|
||||
paddingTop: 40,
|
||||
},
|
||||
centered: { flex: 1, alignItems: 'center', justifyContent: 'center' },
|
||||
backBtn: { alignSelf: 'flex-end', marginBottom: 16, marginRight: 24 },
|
||||
title: { fontSize: 24, fontWeight: 'bold', color: COLORS.textPrimary, marginBottom: 24 },
|
||||
|
||||
@@ -50,6 +50,8 @@ const MenuScreen = () => {
|
||||
navigation.navigate('LoanRemainingOrders');
|
||||
} else if (item.id === 3) {
|
||||
navigation.navigate('LoanPaidOffLetterOrders');
|
||||
} else if (item.id === 5) {
|
||||
navigation.navigate('CardTransactionOrders');
|
||||
} else {
|
||||
console.log('Menu item pressed:', item.title);
|
||||
}
|
||||
|
||||
@@ -214,6 +214,64 @@ class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Card Transactions Orders (Kart hereketleri)
|
||||
// ================================
|
||||
|
||||
async getCardTransactionOrders() {
|
||||
try {
|
||||
const data = await authService.getCardTransactionOrders();
|
||||
return { success: true, data };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async createCardTransactionOrder(cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) {
|
||||
try {
|
||||
const response = await authService.createCardTransactionOrder(cardNumber, cardMonth, cardYear, passportSerie, passportId);
|
||||
return { success: true, message: response.message };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async getCardTransactionOrder(orderId) {
|
||||
try {
|
||||
const data = await authService.getCardTransactionOrder(orderId);
|
||||
return { success: true, data };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async updateCardTransactionOrder(orderId, cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) {
|
||||
try {
|
||||
const response = await authService.updateCardTransactionOrder(orderId, cardNumber, cardMonth, cardYear, passportSerie, passportId);
|
||||
return { success: true, message: response.message };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async deleteCardTransactionOrder(orderId) {
|
||||
try {
|
||||
const response = await authService.deleteCardTransactionOrder(orderId);
|
||||
return { success: true, message: response.message };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async downloadCardTransactions(orderId, startDate, endDate) {
|
||||
try {
|
||||
const response = await authService.downloadCardTransactions(orderId, startDate, endDate);
|
||||
return { success: true, data: response };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// Utility methods for common operations
|
||||
async getUserDashboardData() {
|
||||
try {
|
||||
|
||||
@@ -301,6 +301,75 @@ class AuthService {
|
||||
async deleteLoanOrder(orderId) {
|
||||
return this.makeRequest(`/loan-order/${orderId}`, null, true, 'DELETE');
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Card Transactions Orders (Kart hereketleri)
|
||||
// ================================
|
||||
|
||||
// LIST
|
||||
async getCardTransactionOrders() {
|
||||
return this.makeRequest('/card-transactions', null, true, 'GET');
|
||||
}
|
||||
|
||||
// CREATE order (auto-fills passport data from stored profile)
|
||||
async createCardTransactionOrder(cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) {
|
||||
let serie = passportSerie;
|
||||
let pid = passportId;
|
||||
if (!serie || !pid) {
|
||||
const user = await this.getStoredUser();
|
||||
serie = serie || user?.passport_serie;
|
||||
pid = pid || user?.passport_id;
|
||||
}
|
||||
if (!serie || !pid) {
|
||||
throw new Error('Passport details are missing');
|
||||
}
|
||||
const payload = {
|
||||
passport_serie: serie,
|
||||
passport_id: pid,
|
||||
card_number: cardNumber,
|
||||
card_month: cardMonth,
|
||||
card_year: cardYear,
|
||||
};
|
||||
return this.makeRequest('/card-transactions', payload, true, 'POST');
|
||||
}
|
||||
|
||||
// SHOW
|
||||
async getCardTransactionOrder(orderId) {
|
||||
return this.makeRequest(`/card-transactions/${orderId}`, null, true, 'GET');
|
||||
}
|
||||
|
||||
// UPDATE
|
||||
async updateCardTransactionOrder(orderId, cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) {
|
||||
let serie = passportSerie;
|
||||
let pid = passportId;
|
||||
if (!serie || !pid) {
|
||||
const user = await this.getStoredUser();
|
||||
serie = serie || user?.passport_serie;
|
||||
pid = pid || user?.passport_id;
|
||||
}
|
||||
if (!serie || !pid) {
|
||||
throw new Error('Passport details are missing');
|
||||
}
|
||||
const payload = {
|
||||
passport_serie: serie,
|
||||
passport_id: pid,
|
||||
card_number: cardNumber,
|
||||
card_month: cardMonth,
|
||||
card_year: cardYear,
|
||||
};
|
||||
return this.makeRequest(`/card-transactions/${orderId}`, payload, true, 'POST');
|
||||
}
|
||||
|
||||
// DELETE
|
||||
async deleteCardTransactionOrder(orderId) {
|
||||
return this.makeRequest(`/card-transactions/${orderId}`, null, true, 'DELETE');
|
||||
}
|
||||
|
||||
// DOWNLOAD (returns object with url)
|
||||
async downloadCardTransactions(orderId, startDate, endDate) {
|
||||
const query = `start_date=${encodeURIComponent(startDate)}&end_date=${encodeURIComponent(endDate)}`;
|
||||
return this.makeRequest(`/card-transactions-download/${orderId}?${query}`, null, true, 'GET');
|
||||
}
|
||||
}
|
||||
|
||||
export default new AuthService();
|
||||
Reference in New Issue
Block a user