card balance on homepage

This commit is contained in:
2025-07-08 17:00:17 +05:00
parent 7f49211680
commit 23ca758917
4 changed files with 335 additions and 13 deletions

View File

@@ -724,6 +724,209 @@
} }
} }
}, },
"/card-balance-quick-check": {
"get": {
"operationId": "cardBalance.quickCheck",
"summary": "Quick card balance check",
"tags": [
"Sargytlar - Kart - Kart galyndylary"
],
"parameters": [
{
"name": "passport_serie",
"in": "query",
"schema": {
"type": "string",
"enum": [
"I-AS",
"I-MR",
"II-MR",
"I-AH",
"II-AH",
"I-LB",
"II-LB",
"I-BN",
"II-BN",
"I-DZ",
"II-DZ"
]
},
"example": "I-AS"
},
{
"name": "passport_id",
"in": "query",
"schema": {
"type": "number"
},
"example": 379514
},
{
"name": "card_number",
"in": "query",
"schema": {
"type": "string"
},
"example": "9934612100000243"
},
{
"name": "card_month",
"in": "query",
"schema": {
"type": "string",
"enum": [
"01",
"02",
"03",
"04",
"05",
"06",
"07",
"08",
"09",
"10",
"11",
"12"
]
},
"example": "12"
},
{
"name": "card_year",
"in": "query",
"schema": {
"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"
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"data": {
"type": "object"
}
},
"required": [
"status",
"data"
]
},
{
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"message": {
"type": "string"
},
"url": {
"type": "string",
"enum": [
""
]
}
},
"required": [
"status",
"message",
"url"
]
}
]
}
}
}
},
"401": {
"$ref": "#/components/responses/AuthenticationException"
},
"422": {
"$ref": "#/components/responses/ValidationException"
}
}
}
},
"/card-balances": { "/card-balances": {
"get": { "get": {
"operationId": "cardBalance.index", "operationId": "cardBalance.index",
@@ -6795,6 +6998,9 @@
}, },
"card_year": { "card_year": {
"type": "string" "type": "string"
},
"card_name": {
"type": "string"
} }
}, },
"required": [ "required": [
@@ -6804,7 +7010,8 @@
"passport_id", "passport_id",
"card_number", "card_number",
"card_month", "card_month",
"card_year" "card_year",
"card_name"
], ],
"title": "ProfileResponse" "title": "ProfileResponse"
}, },
@@ -6947,6 +7154,11 @@
"2090" "2090"
], ],
"example": "2049" "example": "2049"
},
"card_name": {
"type": "string",
"example": "Nurmuhammet Allanov",
"maxLength": 255
} }
}, },
"required": [ "required": [

View File

@@ -19,6 +19,14 @@ const HomeScreen = () => {
const { user, logout } = useAuth(); const { user, logout } = useAuth();
const [metrics, setMetrics] = useState(null); const [metrics, setMetrics] = useState(null);
const [loadingMetrics, setLoadingMetrics] = useState(true); const [loadingMetrics, setLoadingMetrics] = useState(true);
const [cardBalance, setCardBalance] = useState(null);
const [loadingCardBalance, setLoadingCardBalance] = useState(true);
const [cardBalanceError, setCardBalanceError] = useState(null);
const [isBalanceVisible, setIsBalanceVisible] = useState(true);
const showBalanceCard = !loadingCardBalance && cardBalanceError === null && cardBalance !== null;
// (Optional) Add helpers here if needed in the future
useEffect(() => { useEffect(() => {
const fetchMetrics = async () => { const fetchMetrics = async () => {
@@ -39,6 +47,38 @@ const HomeScreen = () => {
fetchMetrics(); fetchMetrics();
}, []); }, []);
useEffect(() => {
const fetchCardBalance = async () => {
// Ensure user has filled all required card & passport fields
if (!user?.passport_serie || !user?.passport_id || !user?.card_number || !user?.card_month || !user?.card_year) {
setLoadingCardBalance(false);
return;
}
try {
const res = await apiService.getCardBalanceQuickCheck();
if (res.success) {
// Try common balance keys else fallback to raw
const raw = res.data;
let balanceValue = null;
if (raw && typeof raw === 'object') {
balanceValue = raw.balance ?? raw.card_balance ?? raw.amount ?? null;
}
setCardBalance(balanceValue);
setCardBalanceError(null);
} else {
console.warn('Failed to fetch card balance:', res.error);
setCardBalanceError(res.error || 'Error');
}
} catch (e) {
console.warn('Error fetching card balance:', e);
} finally {
setLoadingCardBalance(false);
}
};
fetchCardBalance();
}, [user]);
return ( return (
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container}>
<StatusBar style="dark" /> <StatusBar style="dark" />
@@ -67,19 +107,25 @@ const HomeScreen = () => {
</View> </View>
{/* Balance Card */} {/* Balance Card */}
{showBalanceCard && (
<View style={styles.balanceCard}> <View style={styles.balanceCard}>
<View style={styles.balanceHeader}> <View style={styles.balanceHeader}>
<Text style={styles.balanceLabel}>Jemi balans</Text> <Text style={styles.balanceLabel}>Jemi balans</Text>
<TouchableOpacity> <TouchableOpacity onPress={() => setIsBalanceVisible((prev) => !prev)}>
<Ionicons name="eye" size={20} color={COLORS.white} /> <Ionicons name={isBalanceVisible ? 'eye' : 'eye-off'} size={20} color={COLORS.white} />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<Text style={styles.balanceAmount}>1,250.00 TMT</Text> <Text style={styles.balanceAmount}>
{isBalanceVisible ? `${cardBalance} TMT` : '•••••'}
</Text>
<View style={styles.balanceFooter}> <View style={styles.balanceFooter}>
<Text style={styles.accountNumber}>Hasap: ****1234</Text> <Text style={styles.accountNumber}>
{user?.card_number ? `Hasap: ****${String(user.card_number).replace(/[^0-9]/g, '').slice(-4)}` : 'Hasap: ----'}
</Text>
<View style={styles.cardChip} /> <View style={styles.cardChip} />
</View> </View>
</View> </View>
)}
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
); );

View File

@@ -165,6 +165,29 @@ class ApiService {
} }
} }
// Quick card balance check
async getCardBalanceQuickCheck(cardNumber = null, cardMonth = null, cardYear = null, passportSerie = null, passportId = null) {
try {
let raw = await authService.getCardBalanceQuickCheck(cardNumber, cardMonth, cardYear, passportSerie, passportId);
// Handle text response that is JSON-stringified
if (typeof raw === 'string') {
try { raw = JSON.parse(raw); } catch (_) {}
}
// When API returns { status: false, message: '...' }
if (raw && raw.status === false) {
return { success: false, error: raw.message || 'Failed', data: raw };
}
// On success, data may be inside raw.data or raw itself
const data = raw?.data ?? raw;
return { success: true, data };
} catch (error) {
return { success: false, error: error.message };
}
}
// ================================ // ================================
// Loan Paid-Off Letter Orders // Loan Paid-Off Letter Orders
// ================================ // ================================

View File

@@ -370,6 +370,47 @@ class AuthService {
const query = `start_date=${encodeURIComponent(startDate)}&end_date=${encodeURIComponent(endDate)}`; const query = `start_date=${encodeURIComponent(startDate)}&end_date=${encodeURIComponent(endDate)}`;
return this.makeRequest(`/card-transactions-download/${orderId}?${query}`, null, true, 'GET'); return this.makeRequest(`/card-transactions-download/${orderId}?${query}`, null, true, 'GET');
} }
// ================================
// Card balance quick check (Kart galyndysy)
// ================================
async getCardBalanceQuickCheck(cardNumber = null, cardMonth = null, cardYear = null, passportSerie = null, passportId = null) {
// Fallback to stored user profile for missing fields
let serie = passportSerie;
let pid = passportId;
let cNumber = cardNumber;
let cMonth = cardMonth;
let cYear = cardYear;
if (!serie || !pid || !cNumber || !cMonth || !cYear) {
const user = await this.getStoredUser();
serie = serie || user?.passport_serie;
pid = pid || user?.passport_id;
cNumber = cNumber || user?.card_number;
cMonth = cMonth || user?.card_month;
cYear = cYear || user?.card_year;
}
if (!serie || !pid || !cNumber || !cMonth || !cYear) {
throw new Error('Card or passport details are missing');
}
// Ensure values are properly formatted
const plainCardNumber = String(cNumber).replace(/[^0-9]/g, '').slice(0, 16);
const monthStr = String(cMonth).padStart(2, '0');
const payload = {
passport_serie: serie,
passport_id: pid,
card_number: plainCardNumber,
card_month: monthStr,
card_year: String(cYear),
};
// POST request authenticated (token header will be included if available)
return this.makeRequest('/card-balance-quick-check', payload, true, 'POST');
}
} }
export default new AuthService(); export default new AuthService();