Merge branch 'main' of https://git.zeptic.in/rohit/Procurelinc into etenderMerge

This commit is contained in:
Abin Toppo
2026-01-08 11:31:21 +05:30
29 changed files with 2881 additions and 861 deletions
+73 -248
View File
@@ -30,7 +30,7 @@
"react-native": "0.79.0",
"react-native-alert-notification": "^0.4.2",
"react-native-app-intro-slider": "^4.0.4",
"react-native-bouncy-checkbox": "^4.1.3",
"react-native-bouncy-checkbox": "^4.1.2",
"react-native-date-picker": "^5.0.13",
"react-native-gesture-handler": "^2.30.0",
"react-native-gifted-charts": "^1.4.70",
@@ -55,7 +55,7 @@
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native-community/cli": "^18.0.1",
"@react-native-community/cli": "18.0.0",
"@react-native-community/cli-platform-android": "18.0.0",
"@react-native-community/cli-platform-ios": "18.0.0",
"@react-native/babel-preset": "0.79.0",
@@ -105,6 +105,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -136,6 +137,7 @@
"integrity": "sha512-fcdRcWahONYo+JRnJg1/AekOacGvKx12Gu0qXJXFi2WBqQA1i7+O5PaxRB7kxE/Op94dExnCiiar6T09pvdHpA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
"eslint-visitor-keys": "^2.1.0",
@@ -2782,18 +2784,19 @@
}
},
"node_modules/@react-native-community/cli": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-18.0.1.tgz",
"integrity": "sha512-nEEYwfyP00j9i4nr/HhwPabDscoBhhCjxDBpcKERi2oTYHcBr3FTu9PV1gbeJCa4vRCHr6b6VgOcVTdy99NddQ==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-18.0.0.tgz",
"integrity": "sha512-DyKptlG78XPFo7tDod+we5a3R+U9qjyhaVFbOPvH4pFNu5Dehewtol/srl44K6Cszq0aEMlAJZ3juk0W4WnOJA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@react-native-community/cli-clean": "18.0.1",
"@react-native-community/cli-config": "18.0.1",
"@react-native-community/cli-doctor": "18.0.1",
"@react-native-community/cli-server-api": "18.0.1",
"@react-native-community/cli-tools": "18.0.1",
"@react-native-community/cli-types": "18.0.1",
"@react-native-community/cli-clean": "18.0.0",
"@react-native-community/cli-config": "18.0.0",
"@react-native-community/cli-doctor": "18.0.0",
"@react-native-community/cli-server-api": "18.0.0",
"@react-native-community/cli-tools": "18.0.0",
"@react-native-community/cli-types": "18.0.0",
"chalk": "^4.1.2",
"commander": "^9.4.1",
"deepmerge": "^4.3.0",
@@ -2812,58 +2815,26 @@
}
},
"node_modules/@react-native-community/cli-clean": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-18.0.1.tgz",
"integrity": "sha512-brXqk//lmA2Vs5lGq9YLhk7X4IYBSrDRte6t1AktouJpCrH4Tp1sl45yJDS2CHOi/OY1oOfI3kA61tXNX5a/5A==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-18.0.0.tgz",
"integrity": "sha512-+k64EnJaMI5U8iNDF9AftHBJW+pO/isAhncEXuKRc6IjRtIh6yoaUIIf5+C98fgjfux7CNRZAMQIkPbZodv2Gw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.1",
"@react-native-community/cli-tools": "18.0.0",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-glob": "^3.3.2"
}
},
"node_modules/@react-native-community/cli-clean/node_modules/@react-native-community/cli-tools": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.1.tgz",
"integrity": "sha512-WxWFXwfYhHR2eYiB4lkHZVC/PmIkRWeVHBQKmn0h1mecr3GrHYO4BzW1jpD5Xt6XZ9jojQ9wE5xrCqXjiMSAIQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"find-up": "^5.0.0",
"launch-editor": "^2.9.1",
"mime": "^2.4.1",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"semver": "^7.5.2"
}
},
"node_modules/@react-native-community/cli-clean/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@react-native-community/cli-config": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-18.0.1.tgz",
"integrity": "sha512-O4DDJVMx+DYfwEgF/6lB4hoI9sVjrYW6AlLqeJY/D2XH2e4yqK/Pr3SAi4sOMgvjvYZKzLHqIQVxx54v+LyMQA==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-18.0.0.tgz",
"integrity": "sha512-GUGvyek06JRF4mfd9zXao9YQW4+H8ny69HznqNXVRtVSIIekFyjOpKQeSEzdcyqJEEa5gej22GOz1JCHMKBccg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.1",
"@react-native-community/cli-tools": "18.0.0",
"chalk": "^4.1.2",
"cosmiconfig": "^9.0.0",
"deepmerge": "^4.3.0",
@@ -2875,7 +2846,7 @@
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config-android/-/cli-config-android-18.0.0.tgz",
"integrity": "sha512-pgnhEO2cmOeb+bBFEBZFYjeFjDTqWoV0JTorTiugj9bb4RQRCl8cr35baVlBGhxAuaio3722CsJ9GRF1oHjP8w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.0",
@@ -2888,7 +2859,7 @@
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config-apple/-/cli-config-apple-18.0.0.tgz",
"integrity": "sha512-6edjTt3mlNMFBuB/Xd6u0O7GEkhJiKvQgmcoBH18FsNy5cpiHDwQsG8EWM5cHeINp1gMK845qq9fFsTko6gqyQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.0",
@@ -2897,50 +2868,18 @@
"fast-glob": "^3.3.2"
}
},
"node_modules/@react-native-community/cli-config/node_modules/@react-native-community/cli-tools": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.1.tgz",
"integrity": "sha512-WxWFXwfYhHR2eYiB4lkHZVC/PmIkRWeVHBQKmn0h1mecr3GrHYO4BzW1jpD5Xt6XZ9jojQ9wE5xrCqXjiMSAIQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"find-up": "^5.0.0",
"launch-editor": "^2.9.1",
"mime": "^2.4.1",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"semver": "^7.5.2"
}
},
"node_modules/@react-native-community/cli-config/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@react-native-community/cli-doctor": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-18.0.1.tgz",
"integrity": "sha512-B1UWpiVeJ45DX0ip1Et62knAHLzeA1B3XcTJu16PscednnNxV6GBH52kRUoWMsB8HQ8f9IWdFTol8LAp5Y0wwg==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-18.0.0.tgz",
"integrity": "sha512-cD3LJfu2h2QSFmZai+fl7RrORKodd5XHSuB7Y9oF1zkebpRYN720vaUtK+GsepqBOElwKk5gl8uVolJ3j+xm8A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-config": "18.0.1",
"@react-native-community/cli-platform-android": "18.0.1",
"@react-native-community/cli-platform-apple": "18.0.1",
"@react-native-community/cli-platform-ios": "18.0.1",
"@react-native-community/cli-tools": "18.0.1",
"@react-native-community/cli-config": "18.0.0",
"@react-native-community/cli-platform-android": "18.0.0",
"@react-native-community/cli-platform-apple": "18.0.0",
"@react-native-community/cli-platform-ios": "18.0.0",
"@react-native-community/cli-tools": "18.0.0",
"chalk": "^4.1.2",
"command-exists": "^1.2.8",
"deepmerge": "^4.3.0",
@@ -2953,89 +2892,6 @@
"yaml": "^2.2.1"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-config-android": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config-android/-/cli-config-android-18.0.1.tgz",
"integrity": "sha512-1wzmGLfS7qgzm0ZfwX/f6Lat/af8/UYdjwtb3ap6RfKNclvIoap0wN6uBeiANmLfk0/BhoG8K1vKtIPwlU/V1A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.1",
"chalk": "^4.1.2",
"fast-glob": "^3.3.2",
"fast-xml-parser": "^4.4.1"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-config-apple": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-config-apple/-/cli-config-apple-18.0.1.tgz",
"integrity": "sha512-ybr1ZrOSd/Z+oCJ1qVSKVQauvneObTu3VjvYPhhrme7tUUSaYmd3iikaWonbKk5rVp+2WqOFR6Cy7XqVfwwG8A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.1",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-glob": "^3.3.2"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-platform-android": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-18.0.1.tgz",
"integrity": "sha512-DCltVWDR7jfZZG5MXREVKG0fmIr1b0irEhmdkk/R87dG6HJ8tGXWXnAa4Kap8bx2v6lKFXDW5QxNecyyLCOkVw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-config-android": "18.0.1",
"@react-native-community/cli-tools": "18.0.1",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"logkitty": "^0.7.1"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-platform-apple": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-apple/-/cli-platform-apple-18.0.1.tgz",
"integrity": "sha512-7WxGXT/ui7VtyLVjx5rkYkkTMlbufI6p5BdRKjGp/zQDnDzs/0rle0JEHJxwgvs5VQnt+VOnHBMipkQAhydIqQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-config-apple": "18.0.1",
"@react-native-community/cli-tools": "18.0.1",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-xml-parser": "^4.4.1"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-platform-ios": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-18.0.1.tgz",
"integrity": "sha512-GtO1FB+xaz+vcHIdvl94AkD5B8Y+H8XHb6QwnYX+A3WwteGsHrR8iD/bLLcRtNPtLaAWMa/RgWJpgs4KG+eU4w==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-platform-apple": "18.0.1"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/@react-native-community/cli-tools": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.1.tgz",
"integrity": "sha512-WxWFXwfYhHR2eYiB4lkHZVC/PmIkRWeVHBQKmn0h1mecr3GrHYO4BzW1jpD5Xt6XZ9jojQ9wE5xrCqXjiMSAIQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"find-up": "^5.0.0",
"launch-editor": "^2.9.1",
"mime": "^2.4.1",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"semver": "^7.5.2"
}
},
"node_modules/@react-native-community/cli-doctor/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
@@ -3053,7 +2909,7 @@
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-18.0.0.tgz",
"integrity": "sha512-3Y3RleN/des1C3oRS6s6fDvFYKN0KwsLrYFRpVx9vzdDnH1OGyFJOy4DbrruSPtdNiHUpvvHnOOxeLMj0+/tmw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-config-android": "18.0.0",
@@ -3067,7 +2923,7 @@
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-apple/-/cli-platform-apple-18.0.0.tgz",
"integrity": "sha512-zD18gdP5Wr8BSLJ79xtHuPYcg2Vi/nL+WsGsPm7TZjzR5ZU2WbY/tZ+qTGVTQYhQaah+92sU+Dam7gStMrF/fA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-config-apple": "18.0.0",
@@ -3081,20 +2937,20 @@
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-18.0.0.tgz",
"integrity": "sha512-05Nvkkre/4Gao1TYqyP1wGet8td1dAH0CLJKqLNl9Te6ihnrQ8/8OhjIna5xw0iEFr9An8VdLfaPu1Dgv2qAnQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-platform-apple": "18.0.0"
}
},
"node_modules/@react-native-community/cli-server-api": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-18.0.1.tgz",
"integrity": "sha512-ZRy2IjEM4ljP05bZcnXho0sCxVGI/9SkWkLuzXl+cRu/4I8vLRleihn2GJCopg82QHLLrajUCHhpDKE8NJWcRw==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-18.0.0.tgz",
"integrity": "sha512-tdmGV7ZntYmzrXWheZNpAy6dVI2yrsX4sQH+xAzU7lCfKHk6J8GucxedduXnB5qBB4JgSrrbzg2RLNxv5v0S/Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@react-native-community/cli-tools": "18.0.1",
"@react-native-community/cli-tools": "18.0.0",
"body-parser": "^1.20.3",
"compression": "^1.7.1",
"connect": "^3.6.5",
@@ -3106,43 +2962,11 @@
"ws": "^6.2.3"
}
},
"node_modules/@react-native-community/cli-server-api/node_modules/@react-native-community/cli-tools": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.1.tgz",
"integrity": "sha512-WxWFXwfYhHR2eYiB4lkHZVC/PmIkRWeVHBQKmn0h1mecr3GrHYO4BzW1jpD5Xt6XZ9jojQ9wE5xrCqXjiMSAIQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"find-up": "^5.0.0",
"launch-editor": "^2.9.1",
"mime": "^2.4.1",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"semver": "^7.5.2"
}
},
"node_modules/@react-native-community/cli-server-api/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@react-native-community/cli-tools": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.0.tgz",
"integrity": "sha512-oR6FcDEcSDYos79vZy4+Tj8jgAE0Xf5HEiRXMJFGISYLRx7tvslSaK8SodUOW9TZe2bCZOb5QSvj8zeMpORmxg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
@@ -3161,7 +2985,7 @@
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
"devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -3171,34 +2995,15 @@
}
},
"node_modules/@react-native-community/cli-types": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-18.0.1.tgz",
"integrity": "sha512-pGxr/TSP9Xiw2+9TUn3OWLdcuI4+PJozPsCYZVTGWJ96X6Pv7YX/rNy4emIDkaWaFZ7IWgWXUA725KhEINSf3Q==",
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-18.0.0.tgz",
"integrity": "sha512-J84+4IRXl8WlVdoe1maTD5skYZZO9CbQ6LNXEHx1kaZcFmvPZKfjsaxuyQ+8BsSqZnM2izOw8dEWnAp/Zuwb0w==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"joi": "^17.2.1"
}
},
"node_modules/@react-native-community/cli/node_modules/@react-native-community/cli-tools": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-18.0.1.tgz",
"integrity": "sha512-WxWFXwfYhHR2eYiB4lkHZVC/PmIkRWeVHBQKmn0h1mecr3GrHYO4BzW1jpD5Xt6XZ9jojQ9wE5xrCqXjiMSAIQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@vscode/sudo-prompt": "^9.0.0",
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"find-up": "^5.0.0",
"launch-editor": "^2.9.1",
"mime": "^2.4.1",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"semver": "^7.5.2"
}
},
"node_modules/@react-native-community/cli/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
@@ -3213,9 +3018,9 @@
}
},
"node_modules/@react-native-documents/picker": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-11.0.4.tgz",
"integrity": "sha512-lbwcBwXMwZ5eTvNI6j/HqPjyB87moRCA8k7EoLCXF4KsLNt2jYDBXkUONX/WcMRMyQEaJPWB77W2zMCcRdX4jw==",
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-11.0.3.tgz",
"integrity": "sha512-q+vQNT1NtZcFGwsDpTwMKNNcgOEq6foFDGlPQVt8H7KaEjCjC+wTGdXuVSe8JJr2uO9xZR6kJ7aRHReZ4XDRBw==",
"license": "MIT",
"peerDependencies": {
"react": "*",
@@ -3227,6 +3032,7 @@
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.3.2.tgz",
"integrity": "sha512-XwuQoW7/GEgWRMovOQtX3A4PrXhyaZm0lVUiY8qJDvdngjLms9Cpdck6SmGAUNqQwcj2EadHC1HwL0bEyoa/SQ==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"react": ">=16",
"react-native": ">=0.57"
@@ -3657,6 +3463,7 @@
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.26.tgz",
"integrity": "sha512-RhKmeD0E2ejzKS6z8elAfdfwShpcdkYY8zJzvHYLq+wv183BBcElTeyMLcIX6wIn7QutXeI92Yi21t7aUWfqNQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@react-navigation/core": "^7.13.7",
"escape-string-regexp": "^4.0.0",
@@ -3948,6 +3755,7 @@
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -4281,6 +4089,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -4349,6 +4158,7 @@
"integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.18.0",
@@ -4383,6 +4193,7 @@
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.18.0",
@@ -4614,6 +4425,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5286,6 +5098,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6611,6 +6424,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -8809,6 +8623,7 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -11398,6 +11213,7 @@
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin-prettier.js"
},
@@ -11635,6 +11451,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11699,6 +11516,7 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.79.0.tgz",
"integrity": "sha512-fLG/zl/YF30TWTmp2bbo3flHSFGe4WTyVkb7/wJnMEC39jjXVSCxfDtvSUVavhCc03fA/RTkWWvlmg7NEJk7Vg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.79.0",
@@ -11780,13 +11598,12 @@
"license": "MIT"
},
"node_modules/react-native-bouncy-checkbox": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/react-native-bouncy-checkbox/-/react-native-bouncy-checkbox-4.1.3.tgz",
"integrity": "sha512-duS0gN2FuLpAdEPuurWW3G+f9QhKCQTc9R51aQwPYTT6d01B2lZ/yzyzYbpPAv9SY142oieeUZLufPyjuOx3Ww==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/react-native-bouncy-checkbox/-/react-native-bouncy-checkbox-4.1.2.tgz",
"integrity": "sha512-hB7YwCGTNoMpTPOPiP+RWyQH35S6vxUbc7IGEW/Rqyp7GonEyhtqtthmxiphneRXnywMh8CZwND7OnvppJZscg==",
"license": "MIT",
"dependencies": {
"@freakycoder/react-native-bounceable": "^1.0.3",
"react-native-bouncy-checkbox": "^4.1.2"
"@freakycoder/react-native-bounceable": "^1.0.3"
}
},
"node_modules/react-native-date-picker": {
@@ -11804,6 +11621,7 @@
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.30.0.tgz",
"integrity": "sha512-5YsnKHGa0X9C8lb5oCnKm0fLUPM6CRduvUUw2Bav4RIj/C3HcFh4RIUnF8wgG6JQWCL1//gRx4v+LVWgcIQdGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -11865,6 +11683,7 @@
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
"integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -11938,6 +11757,7 @@
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -11948,6 +11768,7 @@
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.12.0.tgz",
"integrity": "sha512-T2KL6RcDSYDRZswh9glRe600Hvaeq240U21eaqv0uxCNmJz05UeFc4YGQgbFPI8XsakPKx3HjNonItxElFy+QA==",
"license": "MIT",
"peer": true,
"dependencies": {
"react-freeze": "^1.0.0",
"react-native-is-edge-to-edge": "^1.1.7",
@@ -11975,6 +11796,7 @@
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.1.tgz",
"integrity": "sha512-ZUD1xwc3Hwo4cOmOLumjJVoc7lEf9oQFlHnLmgccLC19fNm6LVEdtB+Cnip6gEi0PG3wfvVzskViEtrySQP8Fw==",
"license": "MIT",
"peer": true,
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3",
@@ -12082,6 +11904,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -12142,7 +11965,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/redux-persist": {
"version": "6.0.0",
@@ -13619,6 +13443,7 @@
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
+1 -2
View File
@@ -20,7 +20,7 @@ export const apiCall = async <R, D = {}>(
data,
params,
// withCredentials: true,
baseURL: Variable.Main_Base,
// baseURL: Variable.Main_Base,
headers: {
Authentication: `Bearer ${token?.token}`,
'Content-Type': contentType || 'application/json',
@@ -31,7 +31,6 @@ export const apiCall = async <R, D = {}>(
} catch (error: any) {
const errorMessage = error?.response?.data?.error;
{ error?.response?.data?.error && showErrorAlert(error?.response?.data?.error || '') }
console.log(errorMessage, '---------------url error');
if (error?.response?.status === 401) {
store.dispatch(setToken({}));
+18 -6
View File
@@ -2,12 +2,15 @@ import React, { useEffect, useState, useCallback } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import colors from '../../Constant/Color';
import moment from 'moment';
import LottieView from 'lottie-react-native';
interface CountdownTimerProps {
endDate: string; // Expected format: "DD-MM-YYYY HH:mm:ss"
endDate: string;
myStyle?: any
size?: number // Expected format: "DD-MM-YYYY HH:mm:ss"
}
const CountdownTimer: React.FC<CountdownTimerProps> = React.memo(({ endDate }) => {
const CountdownTimer: React.FC<CountdownTimerProps> = React.memo(({ endDate, myStyle = {}, size = 20 }) => {
const calculateTimeLeft = useCallback(() => {
if (!endDate) return null;
@@ -43,8 +46,14 @@ const CountdownTimer: React.FC<CountdownTimerProps> = React.memo(({ endDate }) =
return (
<View style={styles.container}>
<Text style={styles.timerText}>
{timeLeft.days}d {timeLeft.hours}h {timeLeft.minutes}m {timeLeft.seconds}s
<LottieView
source={require('../../lottie/clock.json')}
autoPlay
loop={true}
style={{ width: size, height: size, }}
/>
<Text style={[styles.timerText, myStyle]}>
{timeLeft.days}D {timeLeft.hours}H {timeLeft.minutes}M {timeLeft.seconds}S
</Text>
</View>
);
@@ -58,15 +67,18 @@ const styles = StyleSheet.create({
paddingVertical: 5,
paddingHorizontal: 10,
borderWidth: 1,
borderColor: colors.primary,
borderColor: colors.black,
borderRadius: 25,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
timerText: {
fontSize: 14,
fontWeight: 'bold',
color: colors.primary,
color: colors.black,
paddingLeft: 5
},
expiredText: {
fontSize: 12,
+1 -1
View File
@@ -50,7 +50,7 @@ const InsideHeader: React.FC<HeaderProps> = ({ title, showArrow = false }) => {
<Text style={styles.title}>{title}</Text>
</View>
<TouchableOpacity onPress={() => { navigation.navigate(NavigationString.Emd) }}>
<TouchableOpacity onPress={() => { navigation.navigate(NavigationString.Home) }}>
<Image
source={ImagePath.Icon.Logo2}
style={styles.logo}
+122
View File
@@ -0,0 +1,122 @@
import React from 'react';
import {
Modal,
View,
Text,
TouchableOpacity,
StyleSheet,
Pressable,
} from 'react-native';
type ConfirmDialogProps = {
visible: boolean;
title?: string;
message: string;
confirmText?: string;
cancelText?: string;
onConfirm: () => void;
onClose: () => void;
};
const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
visible,
title = 'Confirm',
message,
confirmText = 'Confirm',
cancelText = 'Cancel',
onConfirm,
onClose,
}) => {
return (
<Modal
visible={visible}
transparent
animationType="fade"
statusBarTranslucent
onRequestClose={onClose}
>
{/* Overlay (click to close) */}
<Pressable style={styles.overlay} onPress={onClose}>
{/* Stop propagation */}
<Pressable style={styles.container}>
{/* Title */}
<Text style={styles.title}>{title}</Text>
{/* Message */}
<Text style={styles.message}>{message}</Text>
{/* Actions */}
<View style={styles.actions}>
<TouchableOpacity style={styles.cancelBtn} onPress={onClose}>
<Text style={styles.cancelText}>{cancelText}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.confirmBtn}
onPress={() => {
onConfirm();
onClose();
}}
>
<Text style={styles.confirmText}>{confirmText}</Text>
</TouchableOpacity>
</View>
</Pressable>
</Pressable>
</Modal>
);
};
export default ConfirmDialog;
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center',
},
container: {
width: '85%',
backgroundColor: '#fff',
borderRadius: 12,
padding: 20,
elevation: 5,
},
title: {
fontSize: 18,
fontWeight: '600',
marginBottom: 8,
textAlign: 'center',
},
message: {
fontSize: 15,
color: '#444',
textAlign: 'center',
marginBottom: 20,
},
actions: {
flexDirection: 'row',
justifyContent: 'flex-end',
},
cancelBtn: {
paddingVertical: 10,
paddingHorizontal: 16,
marginRight: 10,
},
cancelText: {
fontSize: 14,
color: '#666',
},
confirmBtn: {
backgroundColor: '#1f4b6dff',
paddingVertical: 10,
paddingHorizontal: 18,
borderRadius: 6,
},
confirmText: {
color: '#fff',
fontSize: 14,
fontWeight: '500',
},
});
+2
View File
@@ -12,6 +12,8 @@ const NavigationString = {
Emd: 'Emd',
StartBidding: 'StartBidding',
PurchaseAuctionList:'PurchaseAuctionList',
StartReverseBidding:'StartReverseBidding'
PurchaseAuctionList:'PurchaseAuctionList',
// tender
PurchaseTenderList:'PurchaseTenderList',
ProceedToPurTender:'ProceedToPurTender',
+1
View File
@@ -40,6 +40,7 @@ export default function MainStack() {
<Stack.Screen name={NavigationString.ProceedToPurTender} component={Screens.ProceedToPurTender} options={option} />
<Stack.Screen name={NavigationString.TenderBidding} component={Screens.TenderBidding} options={option} />
<Stack.Screen name={NavigationString.ProceedToBidDetail} component={Screens.ProceedToBidDetail} options={option} />
<Stack.Screen name={NavigationString.StartReverseBidding} component={Screens.StartReverseBidding} options={option} />
</Stack.Navigator>
);
+2 -14
View File
@@ -1,17 +1,7 @@
import React, { useState, useRef } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Animated,
Dimensions,
} from 'react-native';
import { View, Text, StyleSheet, TouchableOpacity, Animated, Dimensions } from 'react-native';
import { InsideHeader } from '../../Component/Index';
import {
useFetchLiveAuction,
useFetchPurchaseAuction,
} from '../../Services/BBPS/Hooks';
import { useFetchLiveAuction, useFetchPurchaseAuction } from '../../Services/BBPS/Hooks';
import colors from '../../Constant/Color';
import LiveAuction from './LiveAuction';
import PurchaseAuction from './PurchaseAuction';
@@ -20,7 +10,6 @@ import { useNavigation } from '@react-navigation/native';
import NavigationString from '../../Constant/NavigationString';
import FontsFamily from '../../Constant/FontsFamily';
import { useSelector } from 'react-redux';
const { width } = Dimensions.get('screen')
const TAB_WIDTH = 140;
const TAB_HEIGHT = 44;
@@ -30,7 +19,6 @@ const Auction = () => {
const { data: purchaseAuctionData = {} } = useFetchPurchaseAuction();
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
const liveCount = Array.isArray(liveAuctionData?.result)
? liveAuctionData?.pages[0]?.totalCount
: 0;
+39 -2
View File
@@ -9,6 +9,9 @@ import { Skelton } from '../../Component/Index';
import colors from '../../Constant/Color';
import { useDispatch, useSelector } from 'react-redux';
import { selectPurchaseAuctionSlice, togglePurchaseAuction } from '../../Redux/Slices/selectPurchaseAuction';
import { apiCall } from '../../Axios/Axios';
import { GET_MY_AUCTION, LIVE_AUCTION } from '../../Services/BBPS/ApiUrls';
import moment from 'moment';
const LiveAuction = () => {
const navigation: any = useNavigation();
@@ -16,6 +19,7 @@ const LiveAuction = () => {
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch }: any = useFetchLiveAuction();
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
const [allBoolean, setAllBoolean] = useState({ liveAuctionData: [] })
useEffect(() => {
if (isRefetching) {
@@ -64,6 +68,39 @@ const LiveAuction = () => {
[SelectedPurchaseList]
);
const getMyAuction = async () => {
try {
const res = await apiCall<any>('get', `${GET_MY_AUCTION}`,);
if (res?.statusCode === 200) {
const purchasedIds = new Set(
res.data.map((item: any) => item.auctionId),
);
const filteredLive = data?.result.map((item: any) => ({
...item,
active: !purchasedIds.has(item.auctionId), // false if match, true otherwise
}));
setAllBoolean(prev => ({
...prev,
liveAuctionData: filteredLive
}));
}
} catch (error) {
console.error('getMyAuction error', error);
} finally {
setAllBoolean(prev => ({ ...prev, isLoading: false }));
}
};
useEffect(() => {
if (data?.result?.length > 0) {
getMyAuction()
}
}, [data])
if (isLoading) {
return <Skelton />;
}
@@ -110,8 +147,8 @@ const LiveAuction = () => {
)}
<FlatList
data={data?.result ?? []}
keyExtractor={(item) => String(item.auctionId)}
data={allBoolean.liveAuctionData ?? []}
keyExtractor={(item: any) => String(item.auctionNumber)}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 50, paddingTop: 10 }}
+15 -11
View File
@@ -22,24 +22,25 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
return (
<View style={styles.cardWrapper}>
{/* Status Tag */}
{
!showDetail ?
<>
<View
style={[
styles.statusTag,
{ backgroundColor: isPurchased ? colors.error : purchaseEnded ? '#94a3b8' : '#4ade80' },
]}
/>
<TouchableOpacity
<View
style={styles.container}
activeOpacity={0.9}
onPress={() => setShowDetail(true)}
>
{/* Header */}
<View style={styles.header}>
<View style={styles.badge}>
<TouchableOpacity style={styles.badge} onPress={() => setShowDetail(true)}>
<Tag size={14} color={colors.primary} />
<Text style={styles.badgeText}>#{auctionNumber}</Text>
</View>
</TouchableOpacity>
<Text style={styles.priceText}>₹{auctionFees}</Text>
</View>
@@ -81,12 +82,12 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
styles.mainButton,
purchaseEnded
? styles.btnDisabled
: isPurchased
: !data.active ? { backgroundColor: 'lightgray' } : isPurchased
? styles.btnPurchased
: styles.btnActive,
]}
onPress={onPurchasePress}
disabled={purchaseEnded}
disabled={purchaseEnded ? true : data.active ? false : true}
>
<Text
style={[
@@ -94,7 +95,7 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
isPurchased && !purchaseEnded ? { color: colors.white } : { color: '#fff' },
]}
>
{purchaseEnded ? 'Expired' : isPurchased ? 'Remove' : 'Add to Cart'}
{purchaseEnded ? 'Expired' : !data.active ? 'Purchased' : isPurchased ? 'Remove' : 'Add to Cart'}
</Text>
{!purchaseEnded && (
<ArrowRight size={16} color={isPurchased ? colors.white : '#fff'} />
@@ -103,8 +104,11 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
</View>
{/* Auction Detail Modal */}
<AuctionDetail visible={showDetail} data={data} onClose={() => setShowDetail(false)} />
</TouchableOpacity>
</View>
</>
: <AuctionDetail visible={showDetail} data={data} onClose={() => setShowDetail(false)} />
}
</View>
);
};
+13 -31
View File
@@ -1,30 +1,8 @@
import React, { memo, useState } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ScrollView,
SafeAreaView,
Platform,
StatusBar,
} from 'react-native';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, SafeAreaView, Platform, StatusBar } from 'react-native';
import Modal from 'react-native-modal';
import moment from 'moment';
import {
X,
Hash,
Briefcase,
Calendar,
CreditCard,
FileText,
Download,
Eye,
Layers,
ArrowLeft,
Info,
Clock
} from 'lucide-react-native';
import { Briefcase, Calendar, FileText, Download, Eye, Layers, ArrowLeft, Clock } from 'lucide-react-native';
import colors from '../../../Constant/Color';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import AuctionItemDetail from './AuctionItemDetail';
@@ -69,13 +47,15 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
<Modal
isVisible={visible}
style={styles.fullModal}
animationIn="slideInRight"
animationOut="slideOutRight"
useNativeDriver
hideModalContentWhileAnimating
animationIn="fadeIn"
animationOut="fadeOut"
animationInTiming={360}
animationOutTiming={280}
statusBarTranslucent
backdropColor="transparent"
backdropOpacity={0}
>
<SafeAreaView style={styles.safeArea}>
<View style={styles.safeArea}>
<StatusBar barStyle="dark-content" />
{/* Full Header */}
@@ -191,7 +171,9 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
</Text>
</TouchableOpacity>
</View>
<AuctionItemDetail data={{
<AuctionItemDetail
data={{
productName: "sick sari",
timeDuration: "112 YEAR",
category: "laundry",
@@ -207,7 +189,7 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
description: "Auction of cars",
documentName: "BBPS screens.pdf"
}} onClose={() => { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: false })) }} visible={allBoolean.showItemDetail} />
</SafeAreaView>
</View>
</Modal>
);
};
@@ -79,13 +79,16 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data = ITEM_DUMM
<Modal
isVisible={visible}
style={styles.fullModal}
animationIn="slideInUp"
animationOut="slideOutDown"
backdropOpacity={1}
useNativeDriver
animationIn="fadeIn"
animationOut="fadeOut"
animationInTiming={360}
animationOutTiming={280}
statusBarTranslucent
backdropColor="transparent"
backdropOpacity={0}
useNativeDriver
>
<SafeAreaView style={styles.safeArea}>
<View style={styles.safeArea}>
{/* Navbar */}
<View style={[styles.header, { paddingTop: inset.top }]}>
@@ -171,7 +174,7 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data = ITEM_DUMM
</Section>
</ScrollView>
</SafeAreaView>
</View>
</Modal>
);
};
+2 -2
View File
@@ -11,6 +11,7 @@ import { SearchInput } from '../../Component/Serach/SeacrhInput';
import { Skelton } from '../../Component/Index';
import { allBooleanProps } from './types/types';
import FilterModal from './Modal/FilterModal';
import NavigationString from '../../Constant/NavigationString';
const PurchaseAuction = () => {
@@ -51,11 +52,10 @@ const PurchaseAuction = () => {
<PurchaseAuctionTile
item={item}
onPressDetails={() => {
navigation.navigate('AuctionDetail', { item, onAddToPurchase: () => { }, routeFrom: 'PurchasedAuction' });
}}
onStartBidding={() => {
Dispatch(setAuction(item))
// navigation.navigate(NavigationString, { data: item })
navigation.navigate(NavigationString.Emd)
}}
buttonEnable={isAuctionActive(item)}
isAuctionEnd={isAuctionEnd(item)}
+22 -7
View File
@@ -3,8 +3,12 @@ import { View, Text, FlatList, StyleSheet, TouchableOpacity, Alert } from 'react
import { InsideHeader, Loader } from '../../Component/Index';
import colors from '../../Constant/Color';
import { CreditCard, Calendar, User, DollarSign, ArrowRight } from 'lucide-react-native';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { useOfflineAuctionPurchase } from '../../Services/BBPS/Hooks';
import { showSuccessAlert } from '../../Constant/ShowDailog';
import { clearPurchaseAuction } from '../../Redux/Slices/selectPurchaseAuction';
import { CommonActions, useNavigation } from '@react-navigation/native';
import NavigationString from '../../Constant/NavigationString';
const dummyAuctionList = [
{
@@ -46,6 +50,8 @@ const dummyAuctionList = [
];
const PurchaseAuctionList = () => {
const Navigation = useNavigation()
const Dispatch = useDispatch()
const [loading, setLoading] = useState(false);
const [list, setList] = useState(dummyAuctionList);
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
@@ -81,7 +87,16 @@ const PurchaseAuctionList = () => {
try {
mutate(body, {
onSuccess: (res) => {
console.log(res, '---------------------purchsase response');
if (res.statusCode == 200) {
showSuccessAlert(res.message)
Dispatch(clearPurchaseAuction())
Navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: NavigationString.Home }],
})
);
}
},
onError: (error) => {
console.log(error, "================purchse Error");
@@ -165,16 +180,16 @@ const PurchaseAuctionList = () => {
style={[styles.button, { marginLeft: 8 }]}
onPress={() => handlePurchase('offline')}
>
{
isPending ? <Loader size='small' color={colors.white} /> : <>
<Text style={styles.buttonText}>Purchase Offline</Text>
<ArrowRight size={18} color="#fff" style={{ marginLeft: 6 }} />
</>
}
</TouchableOpacity>
</View>
{loading && (
<View style={styles.loadingOverlay}>
<Loader />
</View>
)}
</View>
);
};
+27 -37
View File
@@ -1,28 +1,13 @@
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Platform,
} from 'react-native';
import Animated, {
FadeInUp,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import Animated, { FadeInUp, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import moment from 'moment';
import CountdownTimer from '../../Component/Counter/CountdownTimer';
import colors from '../../Constant/Color';
import AuctionDetail from './Modal/AuctionDetail';
const PurchaseAuctionTile = ({
item,
onPressDetails,
onStartBidding,
buttonEnable,
isAuctionEnd,
}: any) => {
const PurchaseAuctionTile = ({ item, onPressDetails, onStartBidding, buttonEnable, isAuctionEnd }: any) => {
const [showDetail, setShowDetail] = React.useState(false);
const scale = useSharedValue(1);
const elevation = useSharedValue(8);
@@ -43,26 +28,20 @@ const PurchaseAuctionTile = ({
elevation.value = withTiming(8, { duration: 160 });
};
const statusColor = isAuctionEnd
? '#EF4444'
: buttonEnable
? colors.primary
: '#94A3B8';
const statusColor = isAuctionEnd ? '#EF4444' : buttonEnable ? colors.primary : '#94A3B8';
const lightStatusBg = isAuctionEnd
? '#FEF2F2'
: buttonEnable
? '#EFF6FF'
: '#F8FAFC';
const lightStatusBg = isAuctionEnd ? '#FEF2F2' : buttonEnable ? '#EFF6FF' : '#F8FAFC';
console.log(item?.keyDates?.auctionBidding?.endDateTime, 'kk');
return (
<Animated.View
<View style={{ flex: 1 }}>
{!showDetail ? <Animated.View
entering={FadeInUp.duration(400)}
style={[styles.shadowContainer, animatedStyle]}
>
<TouchableOpacity
activeOpacity={1}
onPress={onPressDetails}
onPress={() => setShowDetail(true)}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
style={styles.cardInternal}
@@ -92,11 +71,19 @@ const PurchaseAuctionTile = ({
{/* Date */}
<View style={styles.dateRow}>
<Text style={styles.dateText}>
<Text style={styles.dateLabel}>Bidding Start: </Text>
{moment(
item?.keyDates?.auctionBidding?.startDateTime?.replace(' kk', ''),
'DD-MM-YYYY HH:mm:ss'
).format('DD MMM YYYY, hh:mm A')}
</Text>
<Text style={styles.dateText}>
<Text style={styles.dateLabel}>Bidding Ends: </Text>
{moment(item?.keyDates?.auctionBidding?.endDateTime).format(
'DD MMM, hh:mm A'
)}
{moment(
item?.keyDates?.auctionBidding?.endDateTime?.replace(' kk', ''),
'DD-MM-YYYY HH:mm:ss'
).format('DD MMM YYYY, hh:mm A')}
</Text>
</View>
@@ -127,14 +114,17 @@ const PurchaseAuctionTile = ({
{isAuctionEnd
? 'Bidding Closed'
: !buttonEnable
? 'Payment Required'
? 'Pending Bid'
: 'Proceed to Start Bidding'}
</Text>
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
</Animated.View>
</Animated.View> :
<AuctionDetail visible={showDetail} data={item} onClose={() => setShowDetail(false)} />
}
</View>
);
};
@@ -0,0 +1,218 @@
import React, { memo, useCallback, useRef } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Platform } from 'react-native';
import Animated, { FadeInUp, Layout, interpolate, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import colors from '../../../Constant/Color';
import AuctionItemDetail from '../../Auction/Modal/AuctionItemDetail';
import MainStyle from '../../../Styles/MainStyle';
const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, SelectedAuction }: any) => {
const [showDetail, setShowDetail] = React.useState(false);
const isMin = bidValue <= item.bidAmount;
// 🔒 Persist expand state safely
const expandedRef = useRef(false);
const animation = useSharedValue(0);
const toggleExpand = useCallback(() => {
expandedRef.current = !expandedRef.current;
animation.value = withSpring(expandedRef.current ? 1 : 0, {
damping: 15,
stiffness: 140,
});
}, []);
const bodyStyle = useAnimatedStyle(() => ({
height: interpolate(animation.value, [0, 1], [0, 190]),
opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]),
marginTop: interpolate(animation.value, [0, 1], [0, 15]),
}));
const arrowStyle = useAnimatedStyle(() => ({
transform: [
{
rotate: `${interpolate(animation.value, [0, 1], [0, 180])}deg`,
},
],
}));
return (
<View>
{
!showDetail ? <Animated.View
layout={Layout.springify()}
entering={FadeInUp.delay(100)}
style={[styles.card, styles.leadingCard, { borderColor: item.me ? '#22C55E' : 'red', backgroundColor: item.me ? "#F0FDF4" : '#fdf0f0ff' }]}
>
{/* HEADER */}
<TouchableOpacity
activeOpacity={0.7}
onPress={() => { setShowDetail(true) }}
style={styles.cardHeader}
>
<View style={{ flex: 1 }}>
<Text style={styles.productName}>{item.productName}</Text>
{/* auctionStartValueFigure */}
<Text style={styles.itemIdText}>
Initial Amt : {item?.auctionStartValueFigure}
</Text>
</View>
<TouchableOpacity style={styles.headerRight} onPress={toggleExpand}>
<View style={[MainStyle.flexBetween, { gap: 10 }]}>
<View style={[styles.badge, item.me ? styles.meBadge : styles.liveBadge]}>
<Text style={[styles.badgeText, item.me ? styles.meText : styles.liveText]}>
{item.me ? 'LEADING' : 'LIVE'}
</Text>
</View>
<Animated.Text style={[styles.arrow, arrowStyle]}>
▼
</Animated.Text>
</View>
<Text style={styles.itemIdText}>
{SelectedAuction?.auctionNumber}
</Text>
</TouchableOpacity>
</TouchableOpacity>
{/* PRICE INFO */}
<View style={styles.priceRow}>
<View>
<Text style={styles.label}>Current Bid</Text>
<Text style={styles.mainPrice}>₹{item?.bidAmount}</Text>
</View>
<View style={{ alignItems: 'flex-end' }}>
<Text style={styles.label}>Increment</Text>
<Text style={styles.incrementText}>
+₹{item.bidVariationValue}
</Text>
</View>
</View>
{/* COLLAPSIBLE BODY */}
<Animated.View style={[styles.collapsibleContainer, bodyStyle]}>
<View style={styles.divider} />
<Text style={styles.bidLabel}>Set Your Bid</Text>
<View style={styles.stepperContainer}>
<TouchableOpacity
onPress={onDecrease}
disabled={isMin}
style={[styles.stepBtn, isMin && styles.disabledBtn]}
>
<Text style={styles.stepText}>−</Text>
</TouchableOpacity>
<View style={styles.inputBox}>
<Text style={styles.currency}>₹</Text>
<Text style={styles.bidValueText}>{bidValue}</Text>
</View>
<TouchableOpacity onPress={onIncrease} style={styles.stepBtn}>
<Text style={styles.stepText}>+</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.submitBtn}
onPress={onPlaceBid}
// activeOpacity={0.85}
>
<Text style={styles.submitBtnText}>Confirm Bid</Text>
</TouchableOpacity>
</Animated.View>
</Animated.View>
:
<AuctionItemDetail data={item} onClose={() => { setShowDetail(false) }} visible={showDetail} />
}
</View>
)
};
export default memo(BiddingCard);
const styles = StyleSheet.create({
card: {
backgroundColor: '#FFF',
borderRadius: 24,
padding: 20,
marginBottom: 16,
borderWidth: 1,
borderColor: '#E2E8F0',
overflow: 'hidden',
...Platform.select({
ios: {
shadowColor: '#000',
shadowOpacity: 0.05,
shadowRadius: 10,
},
android: { elevation: 2 },
}),
},
leadingCard: {
borderColor: '#22C55E',
borderWidth: 2,
backgroundColor: '#F0FDF4',
},
cardHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
},
headerRight: { flexDirection: 'column', alignItems: 'center', gap: 8 },
productName: { fontSize: 18, fontWeight: 'bold', color: '#1E293B' },
itemIdText: { fontSize: 12, color: '#64748B', marginTop: 2 },
badge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 },
liveBadge: { backgroundColor: '#FEE2E2' },
meBadge: { backgroundColor: '#BBF7D0' },
badgeText: { fontSize: 10, fontWeight: '900' },
liveText: { color: '#EF4444' },
meText: { color: '#15803D' },
arrow: { fontSize: 10, color: '#94A3B8' },
priceRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 20 },
label: {
fontSize: 11,
color: '#94A3B8',
textTransform: 'uppercase',
fontWeight: '600',
},
mainPrice: { fontSize: 22, fontWeight: '900', color: '#0F172A' },
incrementText: { fontSize: 16, fontWeight: '700', color: '#3B82F6' },
collapsibleContainer: { overflow: 'hidden' },
divider: { height: 1, backgroundColor: '#E2E8F0', marginVertical: 10 },
bidLabel: { fontSize: 13, fontWeight: '600', color: '#475569', marginBottom: 10 },
stepperContainer: { flexDirection: 'row', gap: 12, marginBottom: 20 },
stepBtn: {
width: 45,
height: 45,
backgroundColor: colors.primary,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
},
disabledBtn: { backgroundColor: '#CBD5E1' },
stepText: { color: '#FFF', fontSize: 20, fontWeight: 'bold' },
inputBox: {
flex: 1,
height: 45,
backgroundColor: '#F1F5F9',
borderRadius: 12,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
currency: { fontSize: 16, fontWeight: 'bold', color: '#64748B', marginRight: 4 },
bidValueText: { fontSize: 18, fontWeight: '800', color: '#0F172A' },
submitBtn: {
height: 50,
backgroundColor: colors.primary,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
},
submitBtnText: { color: '#FFF', fontSize: 16, fontWeight: 'bold' },
});
@@ -0,0 +1,370 @@
import React, { memo, useCallback, useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Platform, TextInput } from 'react-native';
import Animated, { FadeInUp, Layout, interpolate, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import colors from '../../../Constant/Color';
import AuctionItemDetail from '../../Auction/Modal/AuctionItemDetail';
import MainStyle from '../../../Styles/MainStyle';
import axios, { all } from 'axios';
import Variables from '../../../Constant/Variable';
import { useSelector } from 'react-redux';
import { showErrorAlert, showSuccessAlert } from '../../../Constant/ShowDailog';
import { Loader } from '../../../Component/Index';
const ReverseBiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, SelectedAuction, allBoolean, setAllBoolean }: any) => {
const Token = useSelector((state: any) => state.token.token)
const [allState, setAllState] = useState({ isLoading: false })
const [showDetail, setShowDetail] = useState(false);
const [value, setValue] = useState(`${item.bidAmount}`);
const canDecrease = bidValue > item.emdAmount;
const canIncrease = bidValue < item.bidAmount;
// Animation Part Rohit Start
const expandedRef = useRef(false);
const animation = useSharedValue(0);
const toggleExpand = useCallback(() => {
expandedRef.current = !expandedRef.current;
animation.value = withSpring(expandedRef.current ? 1 : 0, {
damping: 15,
stiffness: 140,
});
}, []);
const bodyStyle = useAnimatedStyle(() => ({
height: interpolate(animation.value, [0, 1], [0, 190]),
opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]),
marginTop: interpolate(animation.value, [0, 1], [0, 15]),
}));
const bodyStyle2 = useAnimatedStyle(() => ({
height: interpolate(animation.value, [0, 1], [0, 100]),
opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]),
marginTop: interpolate(animation.value, [0, 1], [0, 15]),
}));
const arrowStyle = useAnimatedStyle(() => ({
transform: [
{
rotate: `${interpolate(animation.value, [0, 1], [0, 180])}deg`,
},
],
}));
// Animation Part Rohit End
const MAX_VALUE = Number(item.auctionStartValue);
const handleChange = (text: string) => {
let cleaned = text.replace(/[^0-9.]/g, '');
if ((cleaned.match(/\./g) || []).length > 1) return;
if (cleaned === '') {
setValue('');
return;
}
const numericValue = Number(cleaned);
if (numericValue < 0) return;
if (numericValue > MAX_VALUE) return;
setValue(cleaned);
};
const oneTimePlaceBid = async () => {
try {
setAllState((prev: any) => ({ ...prev, isLoading: true }))
const payload = {
itemId: item.id,
bidAmount: Number(value),
auctionId: SelectedAuction.auctionId,
contractorId: Token.contractorId,
fullName: Token.fullName,
};
const res = await axios.post(
`${Variables.socketUrl}bidding/placeBidForAuction`,
[payload],
{ headers: { Authentication: `Bearer ${Token.token}` } }
);
if (res.data.statusCode === 200) {
showSuccessAlert(res.data.message);
}
setAllBoolean((prev: any) => ({ ...prev, reload: !prev.reload }))
} catch (error) {
if (axios.isAxiosError(error)) {
showErrorAlert(error.response?.data.message)
} else {
console.log('UNKNOWN ERROR:', error);
}
} finally {
setAllState((prev: any) => ({ ...prev, isLoading: false }))
}
}
return (
<View>
{!showDetail ? (
<Animated.View
layout={Layout.springify()}
entering={FadeInUp.delay(100)}
style={[
styles.card,
{
borderColor: item.me ? '#22C55E' : '#EF4444',
backgroundColor: item.me ? '#F0FDF4' : '#FDF0F0',
},
]}
>
{/* HEADER */}
<TouchableOpacity
activeOpacity={0.7}
onPress={() => setShowDetail(true)}
style={styles.cardHeader}
>
<View style={{ flex: 1 }}>
<Text style={styles.productName}>{item.productName}</Text>
<Text style={styles.itemIdText}>
Initial Amt : ₹{item.auctionStartValue}
</Text>
</View>
<TouchableOpacity style={styles.headerRight} onPress={toggleExpand}>
<View style={[MainStyle.flexBetween, { gap: 10 }]}>
<View
style={[
styles.badge,
item.me ? styles.meBadge : styles.liveBadge,
]}
>
<Text
style={[
styles.badgeText,
item.me ? styles.meText : styles.liveText,
]}
>
{item.me ? 'LEADING' : 'LIVE'}
</Text>
</View>
<Animated.Text style={[styles.arrow, arrowStyle]}>
▼
</Animated.Text>
</View>
<Text style={styles.itemIdText}>
{SelectedAuction?.auctionNumber}
</Text>
</TouchableOpacity>
</TouchableOpacity>
{/* PRICE INFO */}
<View style={styles.priceRow}>
<View>
<Text style={styles.label}>Current Bid</Text>
<Text style={styles.mainPrice}>₹{item.bidAmount || item.auctionStartValue}</Text>
</View>
<View style={{ alignItems: 'flex-end' }}>
<Text style={styles.label}>Decrement</Text>
<Text style={styles.incrementText}>
-₹{item.emdAmount}
</Text>
</View>
</View>
{/* COLLAPSIBLE BODY */}
{/* <Animated.View style={[styles.collapsibleContainer, (allBoolean.oneTimeBid && allBoolean.rebid) ? bodyStyle : (allBoolean.oneTimeBid && !item.me) ? bodyStyle : bodyStyle2]}> */}
<Animated.View style={[styles.collapsibleContainer, bodyStyle]}>
<View style={styles.divider} />
<Text style={styles.bidLabel}>Set Your Bid</Text>
<View style={styles.stepperContainer}>
{/* DECREASE */}
{!allBoolean.oneTimeBid && <TouchableOpacity
onPress={onDecrease}
disabled={!canDecrease}
style={[
styles.stepBtn,
!canDecrease && styles.disabledBtn,
]}
>
<Text style={styles.stepText}>−</Text>
</TouchableOpacity>}
{/* VALUE */}
{!allBoolean.oneTimeBid && <View style={styles.inputBox}>
<Text style={styles.currency}>₹</Text>
<Text style={styles.bidValueText}>{bidValue}</Text>
</View>}
{
(allBoolean.oneTimeBid || allBoolean.rebid) && <View style={styles.inputBox2}>
<Text style={styles.currency2}>₹</Text>
<TextInput
value={value}
onChangeText={handleChange}
keyboardType="decimal-pad"
placeholder="0.00"
style={styles.input}
placeholderTextColor="#94A3B8"
/>
</View>
}
{/* INCREASE */}
{!allBoolean.oneTimeBid && <TouchableOpacity
onPress={onIncrease}
disabled={!canIncrease}
style={[
styles.stepBtn,
!canIncrease && styles.disabledBtn,
]}
>
<Text style={styles.stepText}>+</Text>
</TouchableOpacity>}
</View>
<TouchableOpacity
style={[styles.submitBtn]}
onPress={(allBoolean.oneTimeBid || allBoolean.rebid) ? oneTimePlaceBid : onPlaceBid}
>
{
allState.isLoading ? <Loader size='small' color={colors.white} /> : <Text style={styles.submitBtnText}>Confirm Bid</Text>
}
</TouchableOpacity>
{/* {(allBoolean.oneTimeBid && allBoolean.rebid) ?
<TouchableOpacity
style={[styles.submitBtn]}
onPress={(allBoolean.oneTimeBid || allBoolean.rebid) ? oneTimePlaceBid : onPlaceBid}
>
{
allState.isLoading ? <Loader size='small' color={colors.white} /> : <Text style={styles.submitBtnText}>Confirm Bid</Text>
}
</TouchableOpacity> :
(allBoolean.oneTimeBid && !item.me) ? <TouchableOpacity
style={[styles.submitBtn]}
onPress={(allBoolean.oneTimeBid || allBoolean.rebid) ? oneTimePlaceBid : onPlaceBid}
>
{
allState.isLoading ? <Loader size='small' color={colors.white} /> : <Text style={styles.submitBtnText}>Confirm Bid</Text>
}
</TouchableOpacity> : null
} */}
</Animated.View>
</Animated.View>
) : (
<AuctionItemDetail
data={item}
onClose={() => setShowDetail(false)}
visible={showDetail}
/>
)}
</View>
);
};
export default ReverseBiddingCard;
const styles = StyleSheet.create({
inputBox2: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#F1F5F9',
borderRadius: 12,
height: 45,
paddingHorizontal: 12,
width: '100%'
},
currency2: {
fontSize: 16,
fontWeight: 'bold',
color: '#64748B',
marginRight: 4,
},
input: {
flex: 1,
fontSize: 18,
fontWeight: '700',
color: '#0F172A',
width: '100%'
},
card: {
backgroundColor: '#FFF',
borderRadius: 24,
padding: 20,
marginBottom: 16,
borderWidth: 1,
borderColor: '#E2E8F0',
overflow: 'hidden',
...Platform.select({
ios: {
shadowColor: '#000',
shadowOpacity: 0.05,
shadowRadius: 10,
},
android: { elevation: 2 },
}),
},
leadingCard: {
borderColor: '#22C55E',
borderWidth: 2,
backgroundColor: '#F0FDF4',
},
cardHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
},
headerRight: { flexDirection: 'column', alignItems: 'center', gap: 8 },
productName: { fontSize: 18, fontWeight: 'bold', color: '#1E293B' },
itemIdText: { fontSize: 12, color: '#64748B', marginTop: 2 },
badge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 },
liveBadge: { backgroundColor: '#FEE2E2' },
meBadge: { backgroundColor: '#BBF7D0' },
badgeText: { fontSize: 10, fontWeight: '900' },
liveText: { color: '#EF4444' },
meText: { color: '#15803D' },
arrow: { fontSize: 10, color: '#94A3B8' },
priceRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 20 },
label: {
fontSize: 11,
color: '#94A3B8',
textTransform: 'uppercase',
fontWeight: '600',
},
mainPrice: { fontSize: 22, fontWeight: '900', color: '#0F172A' },
incrementText: { fontSize: 16, fontWeight: '700', color: '#3B82F6' },
collapsibleContainer: { overflow: 'hidden' },
divider: { height: 1, backgroundColor: '#E2E8F0', marginVertical: 10 },
bidLabel: { fontSize: 13, fontWeight: '600', color: '#475569', marginBottom: 10 },
stepperContainer: { flexDirection: 'row', gap: 12, marginBottom: 20 },
stepBtn: {
width: 45,
height: 45,
backgroundColor: colors.primary,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
},
disabledBtn: { backgroundColor: '#CBD5E1' },
stepText: { color: '#FFF', fontSize: 20, fontWeight: 'bold' },
inputBox: {
flex: 1,
height: 45,
backgroundColor: '#F1F5F9',
borderRadius: 12,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
currency: { fontSize: 16, fontWeight: 'bold', color: '#64748B', marginRight: 4 },
bidValueText: { fontSize: 18, fontWeight: '800', color: '#0F172A' },
submitBtn: {
height: 50,
backgroundColor: colors.primary,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
},
submitBtnText: { color: '#FFF', fontSize: 16, fontWeight: 'bold' },
});
@@ -0,0 +1,416 @@
import React, { useState } from 'react'
import { Modal, View, Text, StyleSheet, TextInput, TouchableOpacity, ScrollView } from 'react-native'
import { Formik } from 'formik'
import * as Yup from 'yup'
import { pick } from '@react-native-documents/picker'
import { useSelector } from 'react-redux'
import { apiCall } from '../../../Axios/Axios'
import { TECHNICAL_DOCUMENT_SUBMIT, TECHNICAL_VALUE_SUBMIT } from '../../../Services/BBPS/ApiUrls'
import { Props } from '../Type/BidType'
import colors from '../../../Constant/Color'
import { Loader } from '../../../Component/Index'
import { useNavigation } from '@react-navigation/native'
import NavigationString from '../../../Constant/NavigationString'
const TemplateFormModal: React.FC<Props> = ({ visible, template, setAllBoolean }) => {
if (!template) return null
const SelectedAuction = useSelector((state: any) => state.auction.auction)
const Navigation: any = useNavigation()
const [loading, setLoading] = useState(false)
const initialValues = template.labels.reduce((acc: any, label: any) => {
acc[label.labelName] = ''
return acc
}, {})
const validationSchema = Yup.object(
template.labels.reduce((acc: any, label: any) => {
if (label.mandatory) {
acc[label.labelName] =
label.labelType === '3'
? Yup.mixed().required(`${label.labelName} is required`)
: Yup.string().required(`${label.labelName} is required`)
}
return acc
}, {})
)
const pickFile = async (fieldName: string, setFieldValue: any) => {
try {
const result = await pick({
type: ['application/pdf'],
allowMultiSelection: false,
})
const file = result[0]
setFieldValue(fieldName, {
name: file.name ?? 'document.pdf',
uri: file.uri,
type: 'application/pdf',
size: file.size,
})
} catch (e) {
console.log(e)
}
}
const renderInput = (
label: any,
value: any,
setFieldValue: any,
error?: string,
touched?: boolean
) => {
const showError = touched && error
if (label.labelType === '3') {
return (
<View key={label.labelName} style={styles.field}>
<Text style={styles.label}>
{label.labelName}
{label.mandatory && <Text style={styles.required}> *</Text>}
</Text>
<TouchableOpacity
style={[
styles.filePicker,
showError && styles.errorBorder,
]}
onPress={() =>
pickFile(label.labelName, setFieldValue)
}
>
<Text
style={[
styles.fileText,
value?.name && styles.fileSelected,
]}
>
{value?.name || 'Upload PDF'}
</Text>
</TouchableOpacity>
{showError && (
<Text style={styles.errorText}>{error}</Text>
)}
</View>
)
}
return (
<View key={label.labelName} style={styles.field}>
<Text style={styles.label}>
{label.labelName}
{label.mandatory && <Text style={styles.required}> *</Text>}
</Text>
<TextInput
style={[
styles.input,
showError && styles.errorBorder,
]}
placeholder={`Enter ${label.labelName}`}
placeholderTextColor="#9CA3AF"
value={value}
onChangeText={(text) =>
setFieldValue(label.labelName, text)
}
keyboardType={
label.labelType === '1' || label.labelType === '4'
? 'numeric'
: 'default'
}
/>
{showError && (
<Text style={styles.errorText}>{error}</Text>
)}
</View>
)
}
const onClose = () => {
setAllBoolean((prev: any) => ({
...prev,
technicalDocModalVisible: false,
}))
}
const onSubmit = async (payload: any) => {
try {
const jsonBody = {
auctiontId: SelectedAuction.auctionId,
technicalDocumentTemplateId: payload.templateNameId,
labelValues: [] as any[],
}
const fileFormData = new FormData()
let hasFile = false
Object.entries(payload.values).forEach(
([labelName, labelValue]: any) => {
if (typeof labelValue === 'object' && labelValue?.uri) {
hasFile = true
fileFormData.append(labelName, {
uri: labelValue.uri,
name: labelValue.name,
type: labelValue.type,
} as any)
} else {
jsonBody.labelValues.push({
labelName,
labelValue: String(labelValue),
})
}
}
)
const rs1: any = await apiCall('post', TECHNICAL_VALUE_SUBMIT, jsonBody)
if (hasFile) {
fileFormData.append(
'auctiontId',
String(SelectedAuction.auctionId)
)
fileFormData.append(
'technicalDocumentTemplateId',
String(payload.templateNameId)
)
const res2: any = await apiCall(
'post',
TECHNICAL_DOCUMENT_SUBMIT,
fileFormData,
{},
'multipart/form-data'
)
console.log(res2, '-------------res2');
if (rs1.statusCode == 200 && res2.statusCode == 200) {
Navigation.navigate(NavigationString.StartBidding)
setAllBoolean((prev: any) => ({ ...prev, technicalDocModalVisible: false }))
}
} else {
if (rs1.statusCode == 200) {
Navigation.navigate(NavigationString.StartBidding)
setAllBoolean((prev: any) => ({ ...prev, technicalDocModalVisible: false }))
}
}
} catch (e) {
console.log(e)
} finally {
setLoading(false)
}
}
return (
<Modal visible={visible} animationType="fade" transparent>
<View style={styles.screen}>
<View style={styles.header}>
<View style={styles.headerLeft}>
<Text style={styles.headerTitle}>Technical Documents</Text>
<Text style={styles.headerSubtitle}>
Fill the form, Click save when you're done.
</Text>
</View>
<TouchableOpacity onPress={onClose} style={styles.closeBtn}>
<Text style={styles.closeText}>✕</Text>
</TouchableOpacity>
</View>
<ScrollView contentContainerStyle={styles.content}>
<View style={styles.card}>
<Text style={styles.templateHeading}>Template</Text>
<View style={styles.templateBox}>
<Text style={styles.templateName}>
{template.templateName}
</Text>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(values) => {
setLoading(true)
onSubmit({
templateNameId: template.templateNameId,
auctionIds: template.auctionIds,
values,
})
}}
>
{({ handleSubmit, values, errors, touched, setFieldValue }) => (
<>
{template.labels.map((label: any) =>
renderInput(
label,
values[label.labelName],
setFieldValue,
// errors[label.labelName],
// touched[label.labelName]
)
)}
<View style={styles.submitRow}>
<TouchableOpacity
style={styles.submitBtn}
onPress={() => handleSubmit()}
disabled={loading}
>
{loading ? (
<Loader
size="small"
color={colors.white}
/>
) : (
<Text style={styles.submitText}>
Submit
</Text>
)}
</TouchableOpacity>
</View>
</>
)}
</Formik>
</View>
</View>
</ScrollView>
</View>
</Modal>
)
}
export default TemplateFormModal
const styles = StyleSheet.create({
screen: {
flex: 1,
backgroundColor: '#F9FAFB',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 14,
backgroundColor: '#FFFFFF',
borderBottomWidth: 1,
borderColor: '#E5E7EB',
},
headerLeft: {
flex: 1,
},
headerTitle: {
fontSize: 16,
fontWeight: '700',
color: '#111827',
},
headerSubtitle: {
fontSize: 12,
color: '#6B7280',
marginTop: 2,
},
closeBtn: {
padding: 6,
},
closeText: {
fontSize: 18,
color: '#6B7280',
},
content: {
paddingHorizontal: 16,
},
card: {
backgroundColor: '#FFFFFF',
borderColor: '#E5E7EB',
paddingVertical: 20
},
templateHeading: {
fontSize: 18,
fontWeight: '700',
textAlign: 'center',
marginBottom: 16,
color: '#111827',
},
templateBox: {
borderWidth: 1,
borderColor: '#E5E7EB',
borderRadius: 10,
padding: 16,
},
templateName: {
fontSize: 14,
fontWeight: '700',
color: '#111827',
marginBottom: 12,
},
field: {
marginBottom: 14,
},
label: {
fontSize: 13,
fontWeight: '600',
color: '#374151',
marginBottom: 6,
},
required: {
color: '#EF4444',
},
input: {
backgroundColor: '#FFFFFF',
borderWidth: 1,
borderColor: '#E5E7EB',
borderRadius: 8,
padding: 12,
fontSize: 14,
color: '#111827',
},
filePicker: {
borderWidth: 1,
borderColor: '#E5E7EB',
borderRadius: 8,
padding: 12,
},
fileText: {
color: '#6B7280',
fontSize: 14,
},
fileSelected: {
color: '#111827',
fontWeight: '600',
},
errorText: {
color: '#EF4444',
fontSize: 12,
marginTop: 4,
},
errorBorder: {
borderColor: '#EF4444',
},
submitRow: {
marginTop: 20,
alignItems: 'flex-end',
height:50
},
submitBtn: {
backgroundColor: colors.primary,
paddingVertical: 10,
paddingHorizontal: 22,
borderRadius: 8,
minWidth: 120,
alignItems: 'center',
},
submitText: {
color: '#FFFFFF',
fontWeight: '700',
fontSize: 14,
},
})
+202 -46
View File
@@ -1,37 +1,31 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet, TextInput, Alert } from 'react-native';
import { pick } from '@react-native-documents/picker';
import Animated, { FadeInDown, FadeOutUp, Layout } from 'react-native-reanimated';
// import BouncyCheckbox from 'react-native-bouncy-checkbox';
import { InsideHeader, Skelton } from '../../Component/Index';
import BouncyCheckbox from 'react-native-bouncy-checkbox';
import { InsideHeader, Loader, Skelton } from '../../Component/Index';
import colors from '../../Constant/Color';
import EmdComplete from './Component/EmdComplete';
import NavigationString from '../../Constant/NavigationString';
import { useNavigation } from '@react-navigation/native';
import { useSelector } from 'react-redux';
import { useAuctionItem, useEmdCheck } from '../../Services/BBPS/Hooks';
import { apiCall } from '../../Axios/Axios';
import { AUCTION_ITEM_SUBMIT, CHECK_TECHNICAL_DOCUMENTAION, GET_TECHNICAL_DOCUMENTAION } from '../../Services/BBPS/ApiUrls';
import TemplateFormModal from './Component/TemplateFormModal';
import { SelectedItem } from './Type/BidType';
const DUMMY_AUCTION_ITEMS = [
{ id: 1, productName: 'Iron Scrap Lot A', emdAmount: 50000, itemDocumentName: null },
{ id: 2, productName: 'Steel Rods Lot B', emdAmount: 75000, itemDocumentName: 'old_emd.pdf' },
{ id: 3, productName: 'Copper Wire Lot C', emdAmount: 60000, itemDocumentName: null },
];
type SelectedItem = {
auctionItemId: number;
productImageName: string;
file: {
name: string;
uri: string;
type: string;
} | null;
};
const Emd = () => {
const Navigation: any = useNavigation()
const SelectedAuction = useSelector((state: any) => state.auction.auction)
const [selectedItems, setSelectedItems] = useState<SelectedItem[]>([]);
const [acceptedPolicy, setAcceptedPolicy] = useState(false);
const [isComplete, setIsComplete] = useState(false);
const [allBoolean, setAllBoolean] = useState({ isSubmitEmdLoading: false, isEmdComplete: false, auctionItems: [], technicalDocumentStatus: false, selectTemplate: {}, technicalDocModalVisible: false })
const { mutate } = useEmdCheck()
const { mutate: AuctionItemMutate, isPending } = useAuctionItem()
/* ---------------- Helpers ---------------- */
const isSelected = (id: number) => selectedItems.some(i => i.auctionItemId === id);
const toggleSelect = (item: any, checked: boolean) => {
@@ -70,27 +64,6 @@ const Emd = () => {
};
const handleSubmit = () => {
if (!acceptedPolicy) {
Alert.alert('Policy Required', 'Please accept terms');
return;
}
if (selectedItems.length === 0) {
Alert.alert('Select Item', 'Please select at least one item');
return;
}
for (const item of selectedItems) {
if (!item.productImageName || !item.file) {
Alert.alert('Incomplete', 'Upload documents for all selected items');
return;
}
}
console.log('✅ SUBMITTED:', selectedItems);
setIsComplete(true);
};
/* ---------------- Render Item ---------------- */
const renderItem = ({ item }: any) => {
@@ -141,6 +114,7 @@ const Emd = () => {
updateSelectedItem(item.id, { productImageName: text })
}
style={styles.input}
placeholderTextColor={colors.lightText}
/>
<TouchableOpacity
@@ -163,19 +137,197 @@ const Emd = () => {
);
};
// Api calls
const getAuctionItem = async () => {
try {
setAllBoolean((prev: any) => ({ ...prev, isLoading: true }))
if (SelectedAuction.auctionPattern === 'Forward') {
const payload = { auctionNumber: SelectedAuction.auctionNumber, status: 'Forward' }
AuctionItemMutate(payload, {
onSuccess: (res) => {
if (res.statusCode == 200) {
setAllBoolean((prev: any) => ({ ...prev, auctionItems: Array.isArray(res?.data) ? res.data : [res.data] }))
}
},
onError: (err) => {
}
})
} else if (SelectedAuction.auctionPattern === 'Reverse') {
const payload = { auctionNumber: SelectedAuction.auctionNumber, status: 'Reverse' }
AuctionItemMutate(payload, {
onSuccess: (res) => {
if (res.statusCode == 200) {
setAllBoolean((prev: any) => ({ ...prev, auctionItems: Array.isArray(res?.data) ? res.data : [res.data] }))
}
},
onError: (err) => {
}
})
}
} catch (error) {
console.log('Auction fetch error', error)
} finally {
setAllBoolean((prev: any) => ({ ...prev, isLoading: false }))
}
}
const getTemplateDocumentation = async () => {
try {
if (SelectedAuction.technicalDocReq) {
const res = await apiCall<any>('get', CHECK_TECHNICAL_DOCUMENTAION, {}, { auctionId: SelectedAuction.auctionId })
if (res.data) {
setAllBoolean((prev: any) => ({ ...prev, technicalDocumentStatus: true }))
} else {
const res = await apiCall<any>('get', GET_TECHNICAL_DOCUMENTAION,)
const auctionIdToFind = String(SelectedAuction.auctionId);
const matchedObject = res.data.find((item: any) =>
item.auctionIds
.split(',')
.map((id: any) => id.trim())
.includes(auctionIdToFind)
);
setAllBoolean((prev: any) => ({ ...prev, selectTemplate: matchedObject, technicalDocModalVisible: true }))
}
}
} catch (error) {
console.log('Auction fetch error', error)
} finally {
setAllBoolean((prev: any) => ({ ...prev, isLoading: false }))
}
}
const AlreadyEmdCheck = async () => {
try {
mutate({ auctionNumber: SelectedAuction.auctionNumber }, {
onSuccess: (res => {
console.log(SelectedAuction.auctionNumber, res , SelectedAuction,'iiiiiiiiiiiiiiiiiiiiiiiii');
if (res.statusCode == 200) {
if (res.message == 'No EMD Documents') {
setAllBoolean((prev: any) => ({ ...prev, isEmdComplete: false }))
getAuctionItem()
} else {
if (!SelectedAuction.technicalDocReq) {
setAllBoolean((prev: any) => ({ ...prev, isEmdComplete: true, technicalDocumentStatus: true }))
} else {
setAllBoolean((prev: any) => ({ ...prev, isEmdComplete: true }))
getTemplateDocumentation()
}
}
}
}),
onError: (err) => {
}
})
} catch (error) {
console.log('EMD Check Error:', error)
} finally {
setAllBoolean((prev: any) => ({ ...prev, isLoading: false }))
}
}
const handleSubmit = async () => {
setAllBoolean((prev: any) => ({ ...prev, isSubmitEmdLoading: true }))
if (!acceptedPolicy) {
Alert.alert('Policy Required', 'Please accept terms');
return;
}
if (selectedItems.length === 0) {
Alert.alert('Select Item', 'Please select at least one item');
return;
}
for (const item of selectedItems) {
if (!item.productImageName || !item.file) {
Alert.alert('Incomplete', 'Upload documents for all selected items');
return;
}
}
try {
const formData = new FormData()
formData.append('auctionId', String(SelectedAuction.auctionId))
selectedItems.forEach((item: any) => {
formData.append(
'auctionItemId',
String(item.auctionItemId)
)
formData.append(
'productImageName',
item.productImageName
)
formData.append('files', {
uri: item.file.uri,
name: item.file.name,
type: item.file.type || 'application/pdf',
} as any)
})
const res = await apiCall<any>('post', AUCTION_ITEM_SUBMIT, formData, {}, 'multipart/form-data')
if (res.statusCode == 200) {
if (SelectedAuction.technicalDocReq) {
getTemplateDocumentation()
} else {
if (SelectedAuction.auctionPattern === 'Forward') {
Navigation.navigate(NavigationString.StartBidding)
} else {
Navigation.navigate(NavigationString.StartReverseBidding)
}
}
}
} catch (error) {
console.log('Submit error', error)
Alert.alert('Error', 'Failed to submit EMD')
} finally {
setAllBoolean((prev: any) => ({ ...prev, isSubmitEmdLoading: true }))
}
};
const EmdContinueHandle = async () => {
if (allBoolean.technicalDocumentStatus) {
if (SelectedAuction.auctionPattern === 'Forward') {
Navigation.navigate(NavigationString.StartBidding)
} else {
Navigation.navigate(NavigationString.StartReverseBidding)
}
} else {
getTemplateDocumentation()
}
}
useEffect(() => {
AlreadyEmdCheck()
}, [])
return (
<View style={{ flex: 1, backgroundColor: colors.white }}>
<InsideHeader title="EMD Submission" showArrow />
<View style={styles.container}>
{SelectedAuction.technicalDocReq && allBoolean.technicalDocModalVisible &&
<TemplateFormModal visible={allBoolean.technicalDocModalVisible} allBoolean={allBoolean} setAllBoolean={setAllBoolean} template={allBoolean.selectTemplate} />
}
{false ? (
{isPending ? (
<Skelton />
) : true ? (
<EmdComplete onNext={() => { Navigation.navigate(NavigationString.StartBidding) }} />
) : allBoolean.isEmdComplete ? (
<EmdComplete onNext={EmdContinueHandle} />
) : <>
<FlatList
data={DUMMY_AUCTION_ITEMS}
keyExtractor={item => item.id.toString()}
data={allBoolean.auctionItems}
keyExtractor={(item: any) => item.auctionId}
renderItem={renderItem}
contentContainerStyle={{ paddingBottom: 170 }}
/>
@@ -200,7 +352,10 @@ const Emd = () => {
onPress={handleSubmit}
disabled={!acceptedPolicy}
>
<Text style={styles.submitText}>Submit EMD</Text>
{
allBoolean.isSubmitEmdLoading ? <Loader size='small' color={colors.white} /> : <Text style={styles.submitText}>Submit EMD</Text>
}
</TouchableOpacity>
</View>
</>
@@ -277,6 +432,7 @@ const styles = StyleSheet.create({
padding: 12,
backgroundColor: '#FFFFFF',
fontSize: 14,
color: colors.black
},
uploadBtn: {
+237 -146
View File
@@ -1,154 +1,136 @@
import React, { useEffect, useState, useCallback } from 'react';
import {
View,
Text,
FlatList,
TextInput,
TouchableOpacity,
StyleSheet,
Platform,
Alert,
} from 'react-native';
import React, { useCallback, useEffect, useState } from 'react';
import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text } from 'react-native';
import LottieView from 'lottie-react-native';
import Animated, {
FadeInUp,
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
Layout,
interpolate,
} from 'react-native-reanimated';
import { InsideHeader } from '../../Component/Index';
import colors from '../../Constant/Color';
import { useWebSocketService } from '../../socket/Socket';
import Variables from '../../Constant/Variable';
import { useSelector } from 'react-redux';
import { apiCall } from '../../Axios/Axios';
import { FORWARD_AUCTION_ITEM, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/BBPS/ApiUrls';
import BiddingCard from './Component/BiddingCard';
import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
import NavigationString from '../../Constant/NavigationString';
import CountdownTimer from '../../Component/Counter/CountdownTimer';
import FontsFamily from '../../Constant/FontsFamily';
/* ---------------- Types ---------------- */
interface AuctionItem {
id: number;
productName: string;
auctionStartValueFigure: number;
bidVariationValue: number;
bidAmount: number;
bidAvilable: number;
me: boolean;
const StartBidding = () => {
const SelectedAuction = useSelector((state: any) => state.auction.auction);
const loginUser = useSelector((state: any) => state.token.token)
const Navigation: any = useNavigation()
const [items, setItems] = useState<any>([]);
const [bidValues, setBidValues] = useState<Record<number, number>>({});
const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, bidPayload: {} })
const { subscribe, createRoom, placeBid } = useWebSocketService(
Variables.webSocketUrl,
() => console.log('Connected!'),
(error) => console.log('WebSocket Error:', error),
loginUser.token,
);
const getAllAcutionItems = async () => {
try {
const payload = { auctionNumber: SelectedAuction.auctionNumber };
let auctionItem: any[] = [];
if (SelectedAuction.auctionPattern === 'Forward') {
const res = await apiCall<any>('get', FORWARD_AUCTION_ITEM, {}, payload);
if (res?.statusCode === 200) auctionItem = res.data || [];
} else {
const res = await apiCall<any>('get', REVERSE_AUCTION_ITEM, {}, payload);
if (res?.statusCode === 200) auctionItem = res.data || [];
}
/* ---------------- Dummy Data ---------------- */
const DUMMY_AUCTION = { auctionNumber: 'AUC-2025-001' };
const DUMMY_ITEMS: AuctionItem[] = [
{ id: 1, productName: 'Iron Scrap Lot', auctionStartValueFigure: 20000, bidVariationValue: 500, bidAmount: 20000, bidAvilable: 20000, me: false },
{ id: 2, productName: 'Steel Rod Bundle', auctionStartValueFigure: 35000, bidVariationValue: 1000, bidAmount: 35000, bidAvilable: 35000, me: true },
{ id: 3, productName: 'Copper Wire Roll', auctionStartValueFigure: 15000, bidVariationValue: 250, bidAmount: 15000, bidAvilable: 0, me: false },
];
const selectedRes = await apiCall<any>('get', SELECTED_AUCTION_ITEM, {}, payload);
console.log(selectedRes,'jhhhhhhhhhh');
/* ---------------- Bidding Card ---------------- */
const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid }: any) => {
const [expanded, setExpanded] = useState(false);
const isMin = bidValue <= item.bidAmount;
const uniqueArray: number[] = Array.from(
new Set(selectedRes?.data || [])
);
const animation = useSharedValue(0);
const filteredItems = auctionItem.filter(item =>
uniqueArray.includes(item.id)
);
const toggleExpand = () => {
setExpanded(!expanded);
animation.value = withSpring(expanded ? 0 : 1, { damping: 15 });
};
const bodyStyle = useAnimatedStyle(() => {
const result = await createRoom(SelectedAuction.auctionNumber);
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => {
console.log('🔥 BID UPDATE:', data);
});
const bidAmountMap2 = new Map<number, { bidAmount: number; contractorId: number }>();
(result || []).forEach((r: any) => {
bidAmountMap2.set(r.auctionItemId, {
bidAmount: r.bidAmount,
contractorId: r.contractorId,
});
});
const bidAmountMap = new Map<number, number>();
(result || []).forEach((r: any) => {
bidAmountMap.set(r.auctionItemId, r.bidAmount);
});
const updatedFilteredItems = filteredItems.map(item => {
const bidData = bidAmountMap2.get(item.id);
return {
height: interpolate(animation.value, [0, 1], [0, 190]),
opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]),
marginTop: interpolate(animation.value, [0, 1], [0, 15]),
...item,
bidAmount: bidData?.bidAmount ?? item.auctionStartValueFigure,
bidAvilable: bidData?.bidAmount ?? 0,
me: bidData?.contractorId == loginUser.contractorId ? true : false
};
});
const arrowStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${interpolate(animation.value, [0, 1], [0, 180])}deg` }],
}));
const initialBids: Record<number, number> = {};
updatedFilteredItems.forEach(item => {
initialBids[item.id] = item.bidAmount;
});
setBidValues(initialBids);
setItems(updatedFilteredItems);
return (
<Animated.View
layout={Layout.springify()}
entering={FadeInUp.delay(item.id * 100)}
style={[styles.card, item.me && styles.leadingCard]}
>
{/* Header - Always Visible */}
<TouchableOpacity
activeOpacity={0.7}
onPress={toggleExpand}
style={styles.cardHeader}
>
<View style={{ flex: 1 }}>
<Text style={styles.productName}>{item.productName}</Text>
<Text style={styles.itemIdText}>{DUMMY_AUCTION.auctionNumber}</Text>
</View>
<View style={styles.headerRight}>
<View style={[styles.badge, item.me ? styles.meBadge : styles.liveBadge]}>
<Text style={[styles.badgeText, item.me ? styles.meText : styles.liveText]}>
{item.me ? 'LEADING' : 'LIVE'}
</Text>
</View>
<Animated.Text style={[styles.arrow, arrowStyle]}>▼</Animated.Text>
</View>
</TouchableOpacity>
{/* Main Price Info - Always Visible */}
<View style={styles.priceRow}>
<View>
<Text style={styles.label}>Current Bid</Text>
<Text style={styles.mainPrice}>₹{item.bidAmount.toLocaleString()}</Text>
</View>
<View style={{ alignItems: 'flex-end' }}>
<Text style={styles.label}>Increment</Text>
<Text style={styles.incrementText}>+₹{item.bidVariationValue}</Text>
</View>
</View>
{/* Collapsible Section */}
<Animated.View style={[styles.collapsibleContainer, bodyStyle]}>
<View style={styles.divider} />
<Text style={styles.bidLabel}>Set Your Bid</Text>
<View style={styles.stepperContainer}>
<TouchableOpacity
onPress={onDecrease}
disabled={isMin}
style={[styles.stepBtn, isMin && styles.disabledBtn]}
>
<Text style={styles.stepText}>−</Text>
</TouchableOpacity>
<View style={styles.inputBox}>
<Text style={styles.currency}>₹</Text>
<Text style={styles.bidValueText}>{bidValue.toLocaleString()}</Text>
</View>
<TouchableOpacity onPress={onIncrease} style={styles.stepBtn}>
<Text style={styles.stepText}>+</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.submitBtn}
onPress={onPlaceBid}
activeOpacity={0.8}
>
<Text style={styles.submitBtnText}>Confirm Bid</Text>
</TouchableOpacity>
</Animated.View>
</Animated.View>
);
} catch (error) {
console.error('Error fetching auction items:', error);
}
};
/* ---------------- Main Screen ---------------- */
const StartBidding = () => {
const [items, setItems] = useState<AuctionItem[]>(DUMMY_ITEMS);
const [bidValues, setBidValues] = useState<Record<number, number>>({});
const [showSuccess, setShowSuccess] = useState(false);
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, async (message) => {
// console.log('RAW MESSAGE:', message[message.length - 1]);
const result = message[message.length - 1]
const updatedBidItem = (prev: any[]) =>
prev.map(item =>
item.id === result.auctionItemId
? { ...item, bidAmount: result.bidAmount, me: result.contractorId == loginUser.contractorId ? true : false }
: item
);
setItems(updatedBidItem);
setBidValues(prev => ({
...prev,
[result.auctionItemId]: result.bidAmount,
}));
try {
} catch (err) {
console.log('JSON parse error:', err);
}
});
useEffect(() => {
getAllAcutionItems();
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, (data) => { });
}, []);
useEffect(() => {
const initial: Record<number, number> = {};
items.forEach(item => {
items.forEach((item: any) => {
initial[item.id] = item.bidAmount + item.bidVariationValue;
});
setBidValues(initial);
@@ -158,38 +140,133 @@ const StartBidding = () => {
setBidValues(prev => ({ ...prev, [id]: prev[id] + val }));
};
const handlePlaceBid = (item: AuctionItem) => {
Alert.alert('Confirm', `Place bid for ₹${bidValues[item.id]}?`, [
{ text: 'No' },
const submitBid = async (item: any) => {
const payload = {
itemId: item.id,
bidAmount: bidValues[item.id],
auctionId: SelectedAuction.auctionId,
contractorId: loginUser.contractorId,
fullName: loginUser.fullName,
roomId: SelectedAuction.auctionNumber,
};
setAllBoolean((prev: any) => ({ ...prev, bidPayload: payload, }));
Alert.alert(
'Confirm Bid',
`Are you sure you want to place a bid of ₹${payload.bidAmount}?`,
[
{
text: 'Yes, Bid',
text: 'Cancel',
style: 'cancel',
},
{
text: 'Submit',
onPress: () => {
setItems(prev => prev.map(i => i.id === item.id ? { ...i, bidAmount: bidValues[item.id], me: true } : i));
setShowSuccess(true);
setTimeout(() => setShowSuccess(false), 2000);
}
}
]);
placeBidSubmit(payload);
},
},
],
{ cancelable: true }
);
};
const placeBidSubmit = async (data: any) => {
try {
const result: any = await placeBid(data);
if (result?.status && result.data) {
const updatedBidItem = (prev: any[]) =>
prev.map(item =>
item.id === result.data.auctionItemId
? { ...item, bidAmount: result.data.bidAmount, me: result.data?.contractorId == loginUser.contractorId ? true : false }
: item
);
// setItems(updatedBidItem);
// setBidValues((prev: any) => ({
// ...prev,
// [result.data.auctionItemId]: {
// ...prev[result.data.auctionItemId],
// bidAmount: result.data.bidAmount,
// },
// }));
getAllAcutionItems()
}
} catch (error) {
console.error('Error placing bid:', error);
}
};
useFocusEffect(
useCallback(() => {
const onBackPress = () => {
Alert.alert(
'Confirm',
'Do you want to go back to Dashboard?',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Yes',
onPress: () => {
Navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: NavigationString.Home }],
})
);
},
},
],
{ cancelable: true }
);
return true; // block default back action
};
const subscription = BackHandler.addEventListener(
'hardwareBackPress',
onBackPress
);
return () => subscription.remove();
}, [Navigation])
);
return (
<View style={styles.container}>
<InsideHeader title="Bidding Panel" showArrow />
<View style={styles.container2}>
<Text style={styles.title}>
{SelectedAuction.deptName}
</Text>
<View style={styles.timerWrapper}>
<CountdownTimer
endDate={SelectedAuction.keyDates.auctionBidding.endDateTime}
myStyle={{ fontSize: 30 }}
size={30}
/>
</View>
</View>
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
renderItem={({ item, index }) => (
<BiddingCard
item={item}
item={{ ...item, index }}
bidValue={bidValues[item.id] || 0}
onIncrease={() => handleUpdate(item.id, item.bidVariationValue)}
onDecrease={() => handleUpdate(item.id, -item.bidVariationValue)}
onPlaceBid={() => handlePlaceBid(item)}
onPlaceBid={() => { submitBid(item) }}
SelectedAuction={SelectedAuction}
/>
)}
contentContainerStyle={{ padding: 16 }}
/>
{showSuccess && (
{allBoolean.showSuccess && (
<View style={styles.overlay}>
<LottieView
source={require('../../lottie/Success.json')}
@@ -205,9 +282,23 @@ const StartBidding = () => {
export default StartBidding;
/* ---------------- Modern Styles ---------------- */
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: colors.white },
container2: {
paddingHorizontal: 16,
paddingTop: 12,
paddingBottom: 8,
},
title: {
fontSize: 18,
fontFamily: FontsFamily.poppinsSemiBold,
color: colors.black,
marginBottom: 6,
// textAlign:'center'
},
timerWrapper: {
alignItems: 'center',
},
card: {
backgroundColor: '#FFF',
borderRadius: 24,
+401
View File
@@ -0,0 +1,401 @@
import React, { useCallback, useEffect, useState } from 'react';
import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text, ToastAndroid } from 'react-native';
import LottieView from 'lottie-react-native';
import { InsideHeader } from '../../Component/Index';
import colors from '../../Constant/Color';
import { useWebSocketService } from '../../socket/Socket';
import Variables from '../../Constant/Variable';
import { useSelector } from 'react-redux';
import { apiCall } from '../../Axios/Axios';
import { AUCTION_ONE_TIME_BID, GET_AUCTION_DETAILS, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/BBPS/ApiUrls';
import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
import NavigationString from '../../Constant/NavigationString';
import CountdownTimer from '../../Component/Counter/CountdownTimer';
import FontsFamily from '../../Constant/FontsFamily';
import ReverseBiddingCard from './Component/ReverseBiddingCard';
const StartReverseBidding = () => {
const SelectedAuction = useSelector((state: any) => state.auction.auction);
const loginUser = useSelector((state: any) => state.token.token)
const Navigation: any = useNavigation()
const [items, setItems] = useState<any>([]);
const [bidValues, setBidValues] = useState<Record<number, number>>({});
const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, bidPayload: {}, oneTimeBid: false, rebid: false, reload: false })
const { subscribe, createRoom, placeBid } = useWebSocketService(
Variables.webSocketUrl,
() => console.log('Connected!'),
(error) => console.log('WebSocket Error:', error),
loginUser.token,
);
const getAuction = async () => {
const selectedRes = await apiCall<any>('get', GET_AUCTION_DETAILS, {}, { id: SelectedAuction.auctionId });
if (selectedRes.statusCode == 200 && selectedRes.data.contractorId.length) {
setAllBoolean((prev: any) => ({ ...prev, oneTimeBid: true }))
}
}
const getOneTimeBidValue = async () => {
try {
const selectedRes = await apiCall<any>('get', AUCTION_ONE_TIME_BID, {}, { auctionId: SelectedAuction.auctionId });
if (selectedRes.statusCode == 200) {
return selectedRes.data
} else {
return []
}
} catch (error) {
}
}
const getAllAcutionItems = async () => {
try {
const payload = { auctionNumber: SelectedAuction.auctionNumber };
let auctionItem: any[] = [];
if (SelectedAuction.auctionPattern === 'Reverse') {
const res = await apiCall<any>('get', REVERSE_AUCTION_ITEM, {}, payload);
if (res?.statusCode === 200) auctionItem = res.data || [];
}
const selectedRes = await apiCall<any>('get', SELECTED_AUCTION_ITEM, {}, payload);
const uniqueArray: number[] = Array.from(
new Set(selectedRes?.data || [])
);
const filteredItems = auctionItem.filter(item =>
uniqueArray.includes(item.id)
);
if (SelectedAuction.auctionCategories == 'Live') {
const result = await createRoom(SelectedAuction.auctionNumber);
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => {
console.log('🔥 BID UPDATE:', data);
});
const bidAmountMap2 = new Map<number, { bidAmount: number; contractorId: number }>();
(result || []).forEach((r: any) => {
bidAmountMap2.set(r.auctionItemId, {
bidAmount: r.bidAmount,
contractorId: r.contractorId,
});
});
// Check One Time bid enable butoon
if (SelectedAuction.auctionCategories != 'Live') {
const myBid = result.find(
(bid: any) => bid.contractorId === loginUser.contractorId
);
if (myBid) {
setAllBoolean((prev: any) => ({ ...prev, oneTimeBid: true }))
}
}
const bidAmountMap = new Map<number, number>();
(result || []).forEach((r: any) => {
bidAmountMap.set(r.auctionItemId, r.bidAmount);
});
const updatedFilteredItems = filteredItems.map(item => {
const bidData = bidAmountMap2.get(item.id);
return {
...item,
bidAmount: bidData?.bidAmount ?? item.auctionStartValue,
bidAvilable: bidData?.bidAmount ?? 0,
me: bidData?.contractorId == loginUser.contractorId ? true : false
};
});
const initialBids: Record<number, number> = {};
updatedFilteredItems.forEach(item => {
initialBids[item.id] = item.bidAmount;
});
setBidValues(initialBids);
setItems(updatedFilteredItems);
} else {
let result = []
if (SelectedAuction.rebidAllowed) {
setAllBoolean((prev: any) => ({ ...prev, rebid: true }))
}
if (SelectedAuction.auctionCategories != 'Live') {
result = await getOneTimeBidValue()
}
const bidMap = new Map<number, any>();
result.forEach((bid: any) => {
bidMap.set(bid.auctionItemId, bid);
});
const mergedData = auctionItem.map((item: any) => {
const bid = bidMap.get(item.id);
if (!bid) {
return {
...item,
bidAmount: item.auctionStartValue,
contractorId: item.contractorId,
};
}
return {
...item,
bidAmount: bid.bidAmount,
bidId: bid.bidId,
contractorId: bid.contractorId,
contractorName: bid.contractorName,
me: bid.contractorId === loginUser.contractorId,
bidTime: bid.bidTime,
};
});
const initialBids: Record<number, number> = {};
mergedData.forEach(item => {
initialBids[item.id] = item.bidAmount;
});
setBidValues(initialBids);
setItems(mergedData)
setBidValues(initialBids);
}
} catch (error) {
console.error('Error fetching auction items:', error);
}
};
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, async (message) => {
const result = message[message.length - 1]
const updatedBidItem = (prev: any[]) =>
prev.map(item =>
item.id === result.auctionItemId
? { ...item, bidAmount: result.bidAmount, me: result.contractorId == loginUser.contractorId ? true : false }
: item
);
setItems(updatedBidItem);
setBidValues(prev => ({
...prev,
[result.auctionItemId]: result.bidAmount,
}));
try {
} catch (err) {
console.log('JSON parse error:', err);
}
});
useEffect(() => {
if (SelectedAuction.auctionCategories == 'One-time') {
getAuction()
}
getAllAcutionItems();
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, (data) => { });
}, [allBoolean.reload]);
useEffect(() => {
const initial: Record<number, number> = {};
items.forEach((item: any) => {
initial[item.id] = item.bidAmount + item.bidVariationValue;
});
setBidValues(initial);
}, []);
const handleUpdate = (id: number, val: number) => {
setBidValues(prev => ({ ...prev, [id]: prev[id] + val }));
};
const submitBid = async (item: any) => {
const payload = {
itemId: item.id,
bidAmount: bidValues[item.id],
auctionId: SelectedAuction.auctionId,
contractorId: loginUser.contractorId,
fullName: loginUser.fullName,
roomId: SelectedAuction.auctionNumber,
};
setAllBoolean((prev: any) => ({ ...prev, bidPayload: payload, }));
Alert.alert(
'Confirm Bid',
`Are you sure you want to place a bid of ₹${payload.bidAmount}?`,
[
{
text: 'Cancel',
style: 'cancel',
},
{
text: 'Submit',
onPress: () => {
placeBidSubmit(payload);
},
},
],
{ cancelable: true }
);
};
const placeBidSubmit = async (data: any) => {
try {
const result: any = await placeBid(data);
console.log(result, 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk');
if (result?.status && result.data) {
const updatedBidItem = (prev: any[]) =>
prev.map(item =>
item.id === result.data.auctionItemId
? { ...item, bidAmount: result.data.bidAmount, me: result.data?.contractorId == loginUser.contractorId ? true : false }
: item
);
getAllAcutionItems()
}
} catch (error) {
console.error('Error placing bid:', error);
}
};
useFocusEffect(
useCallback(() => {
const onBackPress = () => {
Alert.alert(
'Confirm',
'Do you want to go back to Dashboard?',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Yes',
onPress: () => {
Navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: NavigationString.Home }],
})
);
},
},
],
{ cancelable: true }
);
return true; // block default back action
};
const subscription = BackHandler.addEventListener(
'hardwareBackPress',
onBackPress
);
return () => subscription.remove();
}, [Navigation])
);
return (
<View style={styles.container}>
<InsideHeader title="Bidding Panel" showArrow />
<View style={styles.container2}>
<Text style={styles.title}>
{SelectedAuction.deptName}
</Text>
<View style={styles.timerWrapper}>
<CountdownTimer
endDate={SelectedAuction.keyDates.auctionBidding.endDateTime}
myStyle={{ fontSize: 30 }}
size={30}
/>
</View>
</View>
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item, index }) => (
<ReverseBiddingCard
item={{ ...item, index }}
bidValue={bidValues[item.id] || 0}
onIncrease={() => handleUpdate(item.id, item.emdAmount)}
onDecrease={() => handleUpdate(item.id, -item.emdAmount)}
onPlaceBid={() => { submitBid(item) }}
SelectedAuction={SelectedAuction}
allBoolean={allBoolean}
setAllBoolean={setAllBoolean}
/>
)}
contentContainerStyle={{ padding: 16 }}
/>
{allBoolean.showSuccess && (
<View style={styles.overlay}>
<LottieView
source={require('../../lottie/Success.json')}
autoPlay
loop={false}
style={{ width: 200, height: 200 }}
/>
</View>
)}
</View>
);
};
export default StartReverseBidding;
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: colors.white },
container2: {
paddingHorizontal: 16,
paddingTop: 12,
paddingBottom: 8,
},
title: {
fontSize: 18,
fontFamily: FontsFamily.poppinsSemiBold,
color: colors.black,
marginBottom: 6,
// textAlign:'center'
},
timerWrapper: {
alignItems: 'center',
},
card: {
backgroundColor: '#FFF',
borderRadius: 24,
padding: 20,
marginBottom: 16,
borderWidth: 1,
borderColor: '#E2E8F0',
overflow: 'hidden',
...Platform.select({ ios: { shadowColor: '#000', shadowOpacity: 0.05, shadowRadius: 10 }, android: { elevation: 2 } }),
},
leadingCard: { borderColor: '#22C55E', borderWidth: 2, backgroundColor: '#F0FDF4' },
cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start' },
headerRight: { flexDirection: 'row', alignItems: 'center', gap: 8 },
productName: { fontSize: 18, fontWeight: 'bold', color: '#1E293B' },
itemIdText: { fontSize: 12, color: '#64748B', marginTop: 2 },
badge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 },
liveBadge: { backgroundColor: '#FEE2E2' },
meBadge: { backgroundColor: '#BBF7D0' },
badgeText: { fontSize: 10, fontWeight: '900' },
liveText: { color: '#EF4444' },
meText: { color: '#15803D' },
arrow: { fontSize: 10, color: '#94A3B8' },
priceRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 20 },
label: { fontSize: 11, color: '#94A3B8', textTransform: 'uppercase', fontWeight: '600' },
mainPrice: { fontSize: 22, fontWeight: '900', color: '#0F172A' },
incrementText: { fontSize: 16, fontWeight: '700', color: '#3B82F6' },
collapsibleContainer: { overflow: 'hidden' },
divider: { height: 1, backgroundColor: '#E2E8F0', marginVertical: 10 },
bidLabel: { fontSize: 13, fontWeight: '600', color: '#475569', marginBottom: 10 },
stepperContainer: { flexDirection: 'row', gap: 12, marginBottom: 20 },
stepBtn: { width: 45, height: 45, backgroundColor: colors.primary, borderRadius: 12, justifyContent: 'center', alignItems: 'center' },
disabledBtn: { backgroundColor: '#CBD5E1' },
stepText: { color: '#FFF', fontSize: 20, fontWeight: 'bold' },
inputBox: { flex: 1, height: 45, backgroundColor: '#F1F5F9', borderRadius: 12, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },
currency: { fontSize: 16, fontWeight: 'bold', color: '#64748B', marginRight: 4 },
bidValueText: { fontSize: 18, fontWeight: '800', color: '#0F172A' },
submitBtn: { height: 50, backgroundColor: colors.primary, borderRadius: 15, justifyContent: 'center', alignItems: 'center' },
submitBtnText: { color: '#FFF', fontSize: 16, fontWeight: 'bold' },
overlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(255,255,255,0.7)', justifyContent: 'center', alignItems: 'center', zIndex: 99 },
});
+17
View File
@@ -16,3 +16,20 @@ export type allBooleanType = {
acitveItemData: any
timeEnd: boolean
}
export interface Props {
visible: boolean
setAllBoolean: any
allBoolean: any
template: any
}
export type SelectedItem = {
auctionItemId: number;
productImageName: string;
file: {
name: string;
uri: string;
type: string;
} | null;
};
+3 -1
View File
@@ -3,6 +3,7 @@ import PurchaseAuctionList from "./Auction/PurchaseAuctionList";
import PurchaseList from "./Auction/PurchaseList";
import Emd from "./Bidding/Emd";
import StartBidding from "./Bidding/StartBidding";
import StartReverseBidding from "./Bidding/StartReverseBidding";
import Home from "./Home/Home";
import Login from "./Login/Login";
import Onboarding from "./Onboarding/Onboarding";
@@ -28,6 +29,7 @@ const Screens = {
PurchaseTenderList,
ProceedToPurTender,
TenderBidding,
ProceedToBidDetail
ProceedToBidDetail,
StartReverseBidding
}
export default Screens
+3 -1
View File
@@ -41,7 +41,7 @@ const GET_DOCID = `${BASE_URL}eTendering/download/docId?docId=`
const DOWNLOAD_DOC = `${BASE_URL}eTendering/download/docId?docId=`
const TWO_FACTOR_AUTH = `${BASE_URL}contractor/two-factor-auth?status=`
const AUCTION_LOGIN = `https://api.godemo.in/Auction/auction/loginWithoutDecryption`
const GET_AUCTION_DETAILS = `${BASE_URL_Auction}api/auction/getAuction/id?id=`
const GET_AUCTION_DETAILS = `${BASE_URL_Auction}api/auction/getAuction/id`
const TANDER_PURCHASE_STATUS = `https://procurelinc.in/EProcurementSB/tenderPayment/transactionStatus?orderNo=`
const GET_MY_AUCTION = `${BASE_URL_Auction}api/auction/getMyAuction`
const GET_MY_TENDER = "https://procurelinc.in/EProcurementSB/tenderBidding/getAllPurchasedTendersByConId"
@@ -62,6 +62,7 @@ const ITEM_DOCUMENT_DOWNLOAD = `${BASE_URL_Auction}api/auction/home/downloadDocu
// Rohit
const DASHBOARD_COUNT = `${BASE_URL_Auction}api/auction/home/dashboard/counts`
const AUCTION_ONE_TIME_BID =`${BASE_URL_Auction}api/bidding/getBidForAuction`
//tender
@@ -77,6 +78,7 @@ const SUBMIT_ENVELOPE_FILE_B = `${BASE_URL}tenderBidding/addDocumentsEnvelopeB?r
export {
// Rohit
DASHBOARD_COUNT,
AUCTION_ONE_TIME_BID,
ITEM_DOCUMENT_DOWNLOAD,
ITEM_DETAIL,
TECHNICAL_DOCUMENT_SUBMIT,
+1
View File
@@ -1,4 +1,5 @@
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
import { fetchAuctionItem, fetchDashboard, fetchEmdCheck, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseTender, offlineAuctionPurchase, userLogin } from './apis';
import { fetchDashboard, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseTender, offlineAuctionPurchase, userLogin, offlineTenderPurchase, fetchTenderById, proceedToBid } from './apis';
// User
+30 -3
View File
@@ -1,5 +1,5 @@
import axios from "axios";
import { DASHBOARD_COUNT, GET_MY_AUCTION, GET_MY_TENDER, GET_TENDER_DETAILS, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PROCEED_TO_BID, PURCHASE_TENDER_OFFLINE, TENDER_LOGIN } from "./ApiUrls";
import { DASHBOARD_COUNT, EMD_CHECK, FORARD_AUCTION_ITEM, GET_MY_AUCTION, GET_MY_TENDER, GET_TENDER_DETAILS, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PROCEED_TO_BID, PURCHASE_OFFLINE_AUCTION, PURCHASE_TENDER_OFFLINE, REVERSE_AUCTION_ITEM, TENDER_LOGIN } from "./ApiUrls";
import { apiCall } from "../../Axios/Axios";
// User
@@ -31,8 +31,35 @@ export const fetchLiveAuction = async (payload: any): Promise<any> => {
// Auction Purchase offline
export const offlineAuctionPurchase = async (payload: any): Promise<any> => {
try {
const response = await axios.post(PROCEED_PURCHASE_AUCTION, payload);
return response.data;
const response = await apiCall<any>('post', `${PURCHASE_OFFLINE_AUCTION}`, payload);
return response;
} catch (error: any) {
throw error.response?.data || error.message;
}
};
// EMD
export const fetchEmdCheck = async (payload: any): Promise<any> => {
try {
const response = await apiCall<any>('get', `${EMD_CHECK}`, {}, payload);
return response;
} catch (error: any) {
throw error.response?.data || error.message;
}
};
export const fetchAuctionItem = async (payload: any): Promise<any> => {
try {
if (payload.status == 'Reverse') {
const response = await apiCall<any>('get', `${REVERSE_AUCTION_ITEM}`, {}, payload);
return response;
} else {
const response = await apiCall<any>('get', `${FORARD_AUCTION_ITEM}`, {}, payload);
return response;
}
} catch (error: any) {
throw error.response?.data || error.message;
}
File diff suppressed because one or more lines are too long
+10 -12
View File
@@ -51,8 +51,8 @@ const reducer = (state: State, action: Action): State => {
export const useWebSocketService = (
webSocketUrl: string,
onConnectCallback: () => void,
onErrorCallback: (error: string) => void
) => {
onErrorCallback: (error: string) => void,
Token: any) => {
const [state, dispatch] = useReducer(reducer, {
client: null,
subscriptions: new Map(),
@@ -84,7 +84,7 @@ export const useWebSocketService = (
onConnect: () => {
isConnected.current = true;
console.log('✅ WebSocket connected');
// console.log('✅ WebSocket connected');
// 🔁 Flush queued subscriptions
pendingSubscriptions.current.forEach(sub =>
@@ -111,7 +111,7 @@ export const useWebSocketService = (
// 🧠 Queue if not connected
if (!client || !isConnected.current) {
console.log('⏳ Queued subscription:', destination);
// console.log('⏳ Queued subscription:', destination);
pendingSubscriptions.current.push({ destination, callback });
return;
}
@@ -123,7 +123,6 @@ export const useWebSocketService = (
try {
const parsed = JSON.parse(message.body);
console.log('📡 LIVE DATA:', parsed);
callback(parsed);
} catch (e) {
console.error('❌ JSON parse error', e);
@@ -151,7 +150,6 @@ export const useWebSocketService = (
// ================= ROOM =================
const createRoom = async (roomId: any) => {
const Token = useSelector((prev: any) => prev.token.token)
if (!roomId) return;
try {
@@ -160,7 +158,7 @@ export const useWebSocketService = (
null,
{
params: { roomId },
headers: { Authentication: `Bearer ${Token.token}` },
headers: { Authentication: `Bearer ${Token}` },
}
);
@@ -175,11 +173,11 @@ export const useWebSocketService = (
};
const joinRoom = async (roomId: any) => {
const Token = useSelector((prev: any) => prev.token.token)
try {
const { data } = await axios.get(
`${Variables.socketUrl}livebidding/joinRoom?roomId=${roomId}`,
{ headers: { Authentication: `Bearer ${Token.token}` } }
{ headers: { Authentication: `Bearer ${Token}` } }
);
if (data.statusCode === 200) return data.data.bids;
@@ -190,17 +188,17 @@ export const useWebSocketService = (
// ================= BID =================
const placeBid = async (BidDTO: any) => {
const Token = useSelector((prev: any) => prev.token.token)
try {
const res = await axios.post(
`${Variables.socketUrl}livebidding/placeBid`,
BidDTO,
{ headers: { Authentication: `Bearer ${Token.token}` } }
{ headers: { Authentication: `Bearer ${Token}` } }
);
if (res.data.statusCode === 200) {
showSuccessAlert(res.data.message);
return { data: res.data.data, status: true };
return { data: res.data.data, status: true, message: res.data.message };
}
} catch (err: any) {
if (err?.response?.data?.statusCode === 400) {
+340
View File
@@ -0,0 +1,340 @@
// import React, { useCallback, useEffect, useState } from 'react';
// import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text, ToastAndroid } from 'react-native';
// import LottieView from 'lottie-react-native';
// import { InsideHeader } from '../../Component/Index';
// import colors from '../../Constant/Color';
// import { useWebSocketService } from '../../socket/Socket';
// import Variables from '../../Constant/Variable';
// import { useSelector } from 'react-redux';
// import { apiCall } from '../../Axios/Axios';
// import { FORWARD_AUCTION_ITEM, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/BBPS/ApiUrls';
// import BiddingCard from './Component/BiddingCard';
// import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
// import NavigationString from '../../Constant/NavigationString';
// import CountdownTimer from '../../Component/Counter/CountdownTimer';
// import FontsFamily from '../../Constant/FontsFamily';
// const StartBidding = () => {
// const SelectedAuction = useSelector((state: any) => state.auction.auction);
// const loginUser = useSelector((state: any) => state.token.token)
// const Navigation: any = useNavigation()
// const [items, setItems] = useState<any>([]);
// const [bidValues, setBidValues] = useState<Record<number, number>>({});
// const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, bidPayload: {} })
// const { subscribe, createRoom, placeBid } = useWebSocketService(
// Variables.webSocketUrl,
// () => console.log('Connected!'),
// (error) => console.log('WebSocket Error:', error),
// loginUser.token,
// );
// const getAllAcutionItems = async () => {
// try {
// const payload = { auctionNumber: SelectedAuction.auctionNumber };
// let auctionItem: any[] = [];
// if (SelectedAuction.auctionPattern === 'Forward') {
// const res = await apiCall<any>('get', FORWARD_AUCTION_ITEM, {}, payload);
// if (res?.statusCode === 200) auctionItem = res.data || [];
// } else if(SelectedAuction.auctionPattern === 'Reverse') {
// const res = await apiCall<any>('get', REVERSE_AUCTION_ITEM, {}, payload);
// if (res?.statusCode === 200) auctionItem = res.data || [];
// }
// const selectedRes = await apiCall<any>('get', SELECTED_AUCTION_ITEM, {}, payload);
// const uniqueArray: number[] = Array.from(
// new Set(selectedRes?.data || [])
// );
// const filteredItems = auctionItem.filter(item =>
// uniqueArray.includes(item.id)
// );
// const result = await createRoom(SelectedAuction.auctionNumber);
// subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => {
// console.log('🔥 BID UPDATE:', data);
// });
// const bidAmountMap2 = new Map<number, { bidAmount: number; contractorId: number }>();
// (result || []).forEach((r: any) => {
// bidAmountMap2.set(r.auctionItemId, {
// bidAmount: r.bidAmount,
// contractorId: r.contractorId,
// });
// });
// const bidAmountMap = new Map<number, number>();
// (result || []).forEach((r: any) => {
// bidAmountMap.set(r.auctionItemId, r.bidAmount);
// });
// const updatedFilteredItems = filteredItems.map(item => {
// const bidData = bidAmountMap2.get(item.id);
// return {
// ...item,
// bidAmount: bidData?.bidAmount ?? item.auctionStartValueFigure,
// bidAvilable: bidData?.bidAmount ?? 0,
// me: bidData?.contractorId == loginUser.contractorId ? true : false
// };
// });
// const initialBids: Record<number, number> = {};
// updatedFilteredItems.forEach(item => {
// initialBids[item.id] = item.bidAmount;
// });
// setBidValues(initialBids);
// setItems(updatedFilteredItems);
// } catch (error) {
// console.error('Error fetching auction items:', error);
// }
// };
// subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, async (message) => {
// const result = message[message.length - 1]
// const updatedBidItem = (prev: any[]) =>
// prev.map(item =>
// item.id === result.auctionItemId
// ? { ...item, bidAmount: result.bidAmount, me: result.contractorId == loginUser.contractorId ? true : false }
// : item
// );
// setItems(updatedBidItem);
// setBidValues(prev => ({
// ...prev,
// [result.auctionItemId]: result.bidAmount,
// }));
// try {
// } catch (err) {
// console.log('JSON parse error:', err);
// }
// });
// useEffect(() => {
// getAllAcutionItems();
// subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, (data) => { });
// }, []);
// useEffect(() => {
// const initial: Record<number, number> = {};
// items.forEach((item: any) => {
// initial[item.id] = item.bidAmount + item.bidVariationValue;
// });
// setBidValues(initial);
// }, []);
// const handleUpdate = (id: number, val: number) => {
// setBidValues(prev => ({ ...prev, [id]: prev[id] + val }));
// };
// const submitBid = async (item: any) => {
// const payload = {
// itemId: item.id,
// bidAmount: bidValues[item.id],
// auctionId: SelectedAuction.auctionId,
// contractorId: loginUser.contractorId,
// fullName: loginUser.fullName,
// roomId: SelectedAuction.auctionNumber,
// };
// setAllBoolean((prev: any) => ({ ...prev, bidPayload: payload, }));
// Alert.alert(
// 'Confirm Bid',
// `Are you sure you want to place a bid of ₹${payload.bidAmount}?`,
// [
// {
// text: 'Cancel',
// style: 'cancel',
// },
// {
// text: 'Submit',
// onPress: () => {
// placeBidSubmit(payload);
// },
// },
// ],
// { cancelable: true }
// );
// };
// const placeBidSubmit = async (data: any) => {
// try {
// const result: any = await placeBid(data);
// if (result?.status && result.data) {
// const updatedBidItem = (prev: any[]) =>
// prev.map(item =>
// item.id === result.data.auctionItemId
// ? { ...item, bidAmount: result.data.bidAmount, me: result.data?.contractorId == loginUser.contractorId ? true : false }
// : item
// );
// // ToastAndroid.show(result.message, ToastAndroid.SHORT)
// // setItems(updatedBidItem);
// // setBidValues((prev: any) => ({
// // ...prev,
// // [result.data.auctionItemId]: {
// // ...prev[result.data.auctionItemId],
// // bidAmount: result.data.bidAmount,
// // },
// // }));
// getAllAcutionItems()
// }
// } catch (error) {
// console.error('Error placing bid:', error);
// }
// };
// useFocusEffect(
// useCallback(() => {
// const onBackPress = () => {
// Alert.alert(
// 'Confirm',
// 'Do you want to go back to Dashboard?',
// [
// { text: 'Cancel', style: 'cancel' },
// {
// text: 'Yes',
// onPress: () => {
// Navigation.dispatch(
// CommonActions.reset({
// index: 0,
// routes: [{ name: NavigationString.Home }],
// })
// );
// },
// },
// ],
// { cancelable: true }
// );
// return true; // block default back action
// };
// const subscription = BackHandler.addEventListener(
// 'hardwareBackPress',
// onBackPress
// );
// return () => subscription.remove();
// }, [Navigation])
// );
// return (
// <View style={styles.container}>
// <InsideHeader title="Bidding Panel" showArrow />
// <View style={styles.container2}>
// <Text style={styles.title}>
// {SelectedAuction.deptName}
// </Text>
// <View style={styles.timerWrapper}>
// <CountdownTimer
// endDate={SelectedAuction.keyDates.auctionBidding.endDateTime}
// myStyle={{ fontSize: 30 }}
// size={30}
// />
// </View>
// </View>
// <FlatList
// data={items}
// keyExtractor={item => item.id.toString()}
// renderItem={({ item, index }) => (
// <BiddingCard
// item={{ ...item, index }}
// bidValue={bidValues[item.id] || 0}
// onIncrease={() => handleUpdate(item.id, item.bidVariationValue)}
// onDecrease={() => handleUpdate(item.id, -item.bidVariationValue)}
// onPlaceBid={() => { submitBid(item) }}
// SelectedAuction={SelectedAuction}
// />
// )}
// contentContainerStyle={{ padding: 16 }}
// />
// {allBoolean.showSuccess && (
// <View style={styles.overlay}>
// <LottieView
// source={require('../../lottie/Success.json')}
// autoPlay
// loop={false}
// style={{ width: 200, height: 200 }}
// />
// </View>
// )}
// </View>
// );
// };
// export default StartBidding;
// const styles = StyleSheet.create({
// container: { flex: 1, backgroundColor: colors.white },
// container2: {
// paddingHorizontal: 16,
// paddingTop: 12,
// paddingBottom: 8,
// },
// title: {
// fontSize: 18,
// fontFamily: FontsFamily.poppinsSemiBold,
// color: colors.black,
// marginBottom: 6,
// // textAlign:'center'
// },
// timerWrapper: {
// alignItems: 'center',
// },
// card: {
// backgroundColor: '#FFF',
// borderRadius: 24,
// padding: 20,
// marginBottom: 16,
// borderWidth: 1,
// borderColor: '#E2E8F0',
// overflow: 'hidden',
// ...Platform.select({ ios: { shadowColor: '#000', shadowOpacity: 0.05, shadowRadius: 10 }, android: { elevation: 2 } }),
// },
// leadingCard: { borderColor: '#22C55E', borderWidth: 2, backgroundColor: '#F0FDF4' },
// cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start' },
// headerRight: { flexDirection: 'row', alignItems: 'center', gap: 8 },
// productName: { fontSize: 18, fontWeight: 'bold', color: '#1E293B' },
// itemIdText: { fontSize: 12, color: '#64748B', marginTop: 2 },
// badge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 },
// liveBadge: { backgroundColor: '#FEE2E2' },
// meBadge: { backgroundColor: '#BBF7D0' },
// badgeText: { fontSize: 10, fontWeight: '900' },
// liveText: { color: '#EF4444' },
// meText: { color: '#15803D' },
// arrow: { fontSize: 10, color: '#94A3B8' },
// priceRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 20 },
// label: { fontSize: 11, color: '#94A3B8', textTransform: 'uppercase', fontWeight: '600' },
// mainPrice: { fontSize: 22, fontWeight: '900', color: '#0F172A' },
// incrementText: { fontSize: 16, fontWeight: '700', color: '#3B82F6' },
// collapsibleContainer: { overflow: 'hidden' },
// divider: { height: 1, backgroundColor: '#E2E8F0', marginVertical: 10 },
// bidLabel: { fontSize: 13, fontWeight: '600', color: '#475569', marginBottom: 10 },
// stepperContainer: { flexDirection: 'row', gap: 12, marginBottom: 20 },
// stepBtn: { width: 45, height: 45, backgroundColor: colors.primary, borderRadius: 12, justifyContent: 'center', alignItems: 'center' },
// disabledBtn: { backgroundColor: '#CBD5E1' },
// stepText: { color: '#FFF', fontSize: 20, fontWeight: 'bold' },
// inputBox: { flex: 1, height: 45, backgroundColor: '#F1F5F9', borderRadius: 12, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },
// currency: { fontSize: 16, fontWeight: 'bold', color: '#64748B', marginRight: 4 },
// bidValueText: { fontSize: 18, fontWeight: '800', color: '#0F172A' },
// submitBtn: { height: 50, backgroundColor: colors.primary, borderRadius: 15, justifyContent: 'center', alignItems: 'center' },
// submitBtnText: { color: '#FFF', fontSize: 16, fontWeight: 'bold' },
// overlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(255,255,255,0.7)', justifyContent: 'center', alignItems: 'center', zIndex: 99 },
// });