create bill water

This commit is contained in:
hamid zarghami
2026-02-17 09:21:57 +03:30
parent 6238e3e1a7
commit 8eabcf419e
12 changed files with 300 additions and 98 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
VITE_TOKEN_NAME = 'dsc_token' VITE_TOKEN_NAME = 'dsc_token'
VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token' VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token'
# VITE_BASE_URL = 'http://192.168.82.158:4000' VITE_BASE_URL = 'http://172.28.231.88:4000'
VITE_BASE_URL = 'https://api-dzone.danakcorp.com' # VITE_BASE_URL = 'https://api-dzone.danakcorp.com'
# VITE_DANAK_BASE_URL ='http://192.168.1.113:4000' # VITE_DANAK_BASE_URL ='http://192.168.1.113:4000'
VITE_DANAK_BASE_URL ='https://api.danakcorp.com' VITE_DANAK_BASE_URL ='https://api.danakcorp.com'
VITE_SERVICE_ID = '7e3c2f08-b7e7-4402-ae5f-fea99cff56bd' VITE_SERVICE_ID = '7e3c2f08-b7e7-4402-ae5f-fea99cff56bd'
+41 -91
View File
@@ -1,91 +1,41 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 232.8 56.4">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <defs>
viewBox="0 0 961.6 222.5" style="enable-background:new 0 0 961.6 222.5;" xml:space="preserve"> <style>
<style type="text/css"> .cls-1 {
.st0{fill:#1D1D1B;} font-size: 50px;
</style> }
<g>
<g> .cls-1, .cls-2 {
<g> font-family: Roboto-Regular, Roboto;
<g> }
<path class="st0" d="M246,180.4h-8.7v24.3h-3.6v-24.3H225v-2.9h21V180.4z"/>
<path class="st0" d="M279.1,205c-2.7,0-5-0.9-6.7-2.7s-2.6-4.2-2.6-7.2v-0.6c0-2,0.4-3.8,1.1-5.4s1.8-2.8,3.2-3.7 .cls-1, .cls-2, .cls-3 {
s2.9-1.3,4.5-1.3c2.6,0,4.7,0.9,6.1,2.6c1.5,1.7,2.2,4.2,2.2,7.4v1.4h-13.7c0,2,0.6,3.6,1.7,4.8s2.5,1.8,4.2,1.8 fill: #231f20;
c1.2,0,2.3-0.2,3.1-0.7s1.6-1.2,2.2-2l2.1,1.6C285,203.7,282.5,205,279.1,205z M278.7,186.9c-1.4,0-2.6,0.5-3.5,1.5 }
s-1.5,2.4-1.8,4.3h10.1v-0.3c-0.1-1.8-0.6-3.1-1.4-4.1C281.3,187.4,280.1,186.9,278.7,186.9z"/>
<path class="st0" d="M320.4,202.2c1.2,0,2.3-0.4,3.2-1.1c0.9-0.7,1.4-1.7,1.5-2.8h3.3c-0.1,1.2-0.5,2.3-1.2,3.3 .cls-4 {
s-1.7,1.9-2.9,2.5c-1.2,0.6-2.5,0.9-3.9,0.9c-2.8,0-4.9-0.9-6.6-2.8c-1.6-1.8-2.4-4.3-2.4-7.5v-0.6c0-2,0.4-3.7,1.1-5.2 fill: #000;
s1.8-2.7,3.1-3.6c1.4-0.8,2.9-1.3,4.8-1.3c2.3,0,4.1,0.7,5.6,2c1.5,1.4,2.3,3.1,2.4,5.3h-3.3c-0.1-1.3-0.6-2.4-1.5-3.2 }
s-2-1.3-3.3-1.3c-1.8,0-3.1,0.6-4.1,1.9s-1.4,3.1-1.4,5.5v0.7c0,2.3,0.5,4.1,1.4,5.4C317.2,201.6,318.6,202.2,320.4,202.2z"/>
<path class="st0" d="M357,186.9c1.5-1.9,3.5-2.8,6-2.8c4.3,0,6.4,2.4,6.5,7.2v13.4H366v-13.4c0-1.5-0.3-2.5-1-3.2s-1.7-1-3.1-1 .cls-4, .cls-3 {
c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.4v-28.7h3.5V186.9z"/> stroke-width: 0px;
<path class="st0" d="M399.1,184.5l0.1,2.5c1.5-1.9,3.6-2.9,6.1-2.9c4.3,0,6.4,2.4,6.5,7.2v13.4h-3.5v-13.4c0-1.5-0.3-2.5-1-3.2 }
s-1.7-1-3.1-1c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.5v-20.2h3.4V184.5z"/>
<path class="st0" d="M437.3,194.4c0-2,0.4-3.8,1.2-5.3c0.8-1.6,1.9-2.8,3.2-3.7s3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9 .cls-2 {
s2.5,4.4,2.5,7.6v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7c-1.4,0.9-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9s-2.5-4.4-2.5-7.6v-0.2 font-size: 43.1px;
H437.3z M440.8,194.8c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2c1.8,0,3.1-0.7,4.2-2.1s1.6-3.3,1.6-5.8c0-2.2-0.5-4-1.6-5.4 }
s-2.5-2.1-4.2-2.1s-3.1,0.7-4.1,2C441.3,190.3,440.8,192.3,440.8,194.8z"/> </style>
<path class="st0" d="M485.1,204.7h-3.5V176h3.5V204.7z"/> </defs>
<path class="st0" d="M511,194.4c0-2,0.4-3.8,1.2-5.3c0.8-1.5,1.9-2.8,3.2-3.7c1.4-0.9,3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9 <path class="cls-3" d="M71,26.5h-12.1v-3.8h12.1v3.8Z"/>
s2.5,4.4,2.5,7.6v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7s-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9c-1.7-1.9-2.5-4.4-2.5-7.6v-0.2 <path class="cls-4" d="M5.2,42.7H.1v-1.7c0-.6.1-1,.3-1.2.2-.3.6-.4,1-.4s.4,0,.6.2c.2.1.3.3.4.6,0-.3.2-.5.4-.7.2-.2.5-.2.8-.2.5,0,.8.1,1.1.4s.4.7.4,1.3v1.8ZM2.3,42v-1c0-.3,0-.5-.2-.7-.1-.2-.3-.3-.6-.3s-.5,0-.6.2c-.1.2-.2.4-.2.7v1h1.6ZM2.8,42h1.8v-1.1c0-.3,0-.6-.2-.7-.2-.2-.4-.3-.7-.3-.6,0-.9.3-.9,1v1.1Z"/>
H511z M514.4,194.8c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2s3.2-0.7,4.2-2.1c1-1.4,1.5-3.3,1.5-5.8c0-2.2-0.5-4-1.6-5.4 <path class="cls-4" d="M2.7,36.4l-2.6-1.3v-.8l3.2,1.8h1.9v.7h-1.9l-3.2,1.8v-.8l2.6-1.3Z"/>
s-2.5-2.1-4.2-2.1s-3.1,0.7-4.1,2C515,190.3,514.4,192.3,514.4,194.8z"/> <path class="cls-4" d="M5.1,31.2H0v-1.4c0-.4,0-.8.3-1.2.2-.3.5-.6.8-.8.4-.2.8-.3,1.2-.3h.3c.5,0,.9,0,1.3.3s.6.5.8.8c.2.3.3.7.3,1.2v1.4ZM.6,30.5h4v-.7c0-.5-.2-.9-.5-1.2-.3-.3-.8-.4-1.4-.4h-.3c-.6,0-1,.1-1.4.4-.3.3-.5.7-.5,1.2v.8Z"/>
<path class="st0" d="M554.1,194.4c0-3.2,0.7-5.7,2.2-7.5s3.4-2.8,5.8-2.8c2.5,0,4.4,0.9,5.8,2.6l0.2-2.2h3.2v19.7 <path class="cls-4" d="M5.1,17.1v.7l-3.9,2.6h3.9v.7H0v-.7l4-2.6H0v-.7h5.1Z"/>
c0,2.6-0.8,4.7-2.3,6.2c-1.6,1.5-3.6,2.3-6.2,2.3c-1.5,0-2.9-0.3-4.3-0.9c-1.4-0.6-2.5-1.5-3.2-2.6l1.8-2.1 <path class="cls-4" d="M2.7,9.2l.6.6h1.7v.7H0v-.7h2.5L0,7.5v-.8l2.3,2,2.8-2.2v.8l-2.4,1.8Z"/>
c1.5,1.8,3.3,2.7,5.4,2.7c1.7,0,3-0.5,3.9-1.4s1.4-2.3,1.4-4v-1.7c-1.4,1.6-3.3,2.4-5.7,2.4s-4.3-1-5.7-2.9 <polygon class="cls-4" points=".8 24.4 5.1 22.8 5.1 22.1 0 24.1 0 24.7 5.1 26.6 5.1 25.9 .8 24.4"/>
S554.1,197.7,554.1,194.4z M557.6,194.8c0,2.3,0.5,4.1,1.4,5.4c0.9,1.3,2.2,2,3.9,2c2.2,0,3.8-1,4.8-3V190 <polygon class="cls-4" points=".8 13.8 5.1 12.3 5.1 11.6 0 13.5 0 14.1 5.1 16.1 5.1 15.4 .8 13.8"/>
c-1.1-1.9-2.6-2.9-4.8-2.9c-1.7,0-3,0.7-3.9,2C558.1,190.3,557.6,192.2,557.6,194.8z"/> <path class="cls-4" d="M38.2,42.9c0-1.2,0-2.3,0-3.5s0-.4,0-.7c0-.2.1-.3.3-.5.9-.7,1.7-1.5,2.4-2.5,7-9.1,2.3-22.9-8.6-25.2-1-.2-2.1-.3-3.2-.3-6.3,0-12.6,0-18.9,0-.2,0-.4,0-.7,0v-3.6c.2,0,.3,0,.5,0,6.7,0,13.4,0,20.1,0,4.8,0,8.9,1.9,12.3,5.4,3,3.1,4.7,6.8,5.3,11.2,1,7.7-2.6,15.2-8.9,19-.2.1-.3.2-.6.3Z"/>
<path class="st0" d="M604.3,199.6l4.7-15.1h3.7l-8.1,23.3c-1.3,3.4-3.3,5-6,5l-0.7-0.1l-1.3-0.2v-2.8l0.9,0.1 <text class="cls-2" transform="translate(7 42.8) scale(1.2 1)"><tspan x="0" y="0">Z</tspan></text>
c1.2,0,2.1-0.2,2.7-0.7c0.7-0.5,1.2-1.3,1.6-2.6l0.8-2.1l-7.2-20h3.8L604.3,199.6z"/> <text class="cls-1" transform="translate(81.6 42.8) scale(.9 1)"><tspan x="0" y="0">Z O N E</tspan></text>
<path class="st0" d="M688.3,196c-0.3,2.9-1.4,5.1-3.2,6.7c-1.8,1.6-4.2,2.3-7.1,2.3c-3.2,0-5.8-1.2-7.7-3.5s-2.9-5.4-2.9-9.2 </svg>
v-2.6c0-2.5,0.5-4.8,1.4-6.7s2.2-3.4,3.8-4.4s3.6-1.5,5.8-1.5c2.9,0,5.2,0.8,6.9,2.4c1.7,1.6,2.8,3.8,3,6.7h-3.6
c-0.3-2.2-1-3.7-2-4.7s-2.5-1.5-4.4-1.5c-2.3,0-4.1,0.8-5.4,2.5c-1.3,1.7-2,4.1-2,7.2v2.6c0,3,0.6,5.3,1.8,7s3,2.6,5.2,2.6
c2,0,3.5-0.5,4.6-1.4s1.8-2.5,2.1-4.7h3.7V196z"/>
<path class="st0" d="M713,194.4c0-2,0.4-3.8,1.2-5.3s1.9-2.8,3.2-3.7c1.4-0.9,3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9s2.5,4.4,2.5,7.6
v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7s-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9s-2.5-4.4-2.5-7.6v-0.2H713z M716.5,194.8
c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2s3.2-0.7,4.2-2.1c1-1.4,1.5-3.3,1.5-5.8c0-2.2-0.5-4-1.6-5.4s-2.5-2.1-4.2-2.1
s-3.1,0.7-4.1,2C717,190.3,716.5,192.3,716.5,194.8z"/>
<path class="st0" d="M760.3,184.5l0.1,2.2c1.5-1.7,3.5-2.6,6-2.6c2.8,0,4.8,1.1,5.8,3.2c0.7-1,1.5-1.8,2.6-2.4
c1.1-0.6,2.4-0.9,3.8-0.9c4.4,0,6.7,2.3,6.8,7v13.5h-3.5v-13.3c0-1.4-0.3-2.5-1-3.2s-1.8-1.1-3.3-1.1c-1.3,0-2.3,0.4-3.2,1.1
c-0.8,0.8-1.3,1.8-1.5,3.1v13.4h-3.5v-13.2c0-2.9-1.4-4.4-4.3-4.4c-2.3,0-3.8,1-4.7,2.9v14.8h-3.5v-20.2h3.4V184.5z"/>
<path class="st0" d="M828.9,194.8c0,3.1-0.7,5.6-2.1,7.4c-1.4,1.9-3.3,2.8-5.7,2.8c-2.5,0-4.4-0.8-5.8-2.3v9.7h-3.5v-28h3.2
l0.2,2.2c1.4-1.7,3.4-2.6,5.9-2.6c2.4,0,4.3,0.9,5.8,2.7c1.4,1.8,2.1,4.4,2.1,7.6v0.5H828.9z M825.5,194.4
c0-2.3-0.5-4.1-1.5-5.4c-1-1.3-2.3-2-4-2c-2.1,0-3.7,0.9-4.7,2.8v9.7c1,1.8,2.6,2.8,4.7,2.8c1.7,0,3-0.7,4-2
S825.5,197,825.5,194.4z"/>
<path class="st0" d="M867,204.7c-0.2-0.4-0.4-1.1-0.5-2.1c-1.6,1.7-3.5,2.5-5.8,2.5c-2,0-3.6-0.6-4.9-1.7s-1.9-2.6-1.9-4.3
c0-2.1,0.8-3.7,2.4-4.9c1.6-1.2,3.9-1.7,6.8-1.7h3.4v-1.7c0-1.2-0.4-2.2-1.1-2.9c-0.7-0.7-1.8-1.1-3.2-1.1
c-1.2,0-2.3,0.3-3.1,0.9c-0.8,0.6-1.3,1.4-1.3,2.3h-3.5c0-1,0.4-2,1.1-2.9c0.7-0.9,1.7-1.7,2.9-2.2s2.6-0.8,4-0.8
c2.3,0,4.2,0.6,5.5,1.7c1.3,1.2,2,2.8,2.1,4.8v9.3c0,1.9,0.2,3.3,0.7,4.4v0.3H867V204.7z M861.3,202c1.1,0,2.1-0.3,3.1-0.8
c1-0.6,1.7-1.3,2.1-2.2v-4.1h-2.7c-4.2,0-6.4,1.2-6.4,3.7c0,1.1,0.4,1.9,1.1,2.5C859.2,201.7,860.2,202,861.3,202z"/>
<path class="st0" d="M899.9,184.5l0.1,2.5c1.5-1.9,3.6-2.9,6.1-2.9c4.3,0,6.4,2.4,6.5,7.2v13.4h-3.5v-13.4c0-1.5-0.3-2.5-1-3.2
s-1.7-1-3.1-1c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.5v-20.2h3.4V184.5z"/>
<path class="st0" d="M945.6,199.6l4.7-15.1h3.7l-8.1,23.3c-1.3,3.4-3.3,5-6,5l-0.7-0.1l-1.3-0.2v-2.8l0.9,0.1
c1.2,0,2.1-0.2,2.7-0.7c0.7-0.5,1.2-1.3,1.6-2.6l0.8-2.1l-7.2-20h3.8L945.6,199.6z"/>
</g>
</g>
<path class="st0" d="M221.6,148.7V44.1h29.5c9.1,0,17.1,2,24.1,6s12.4,9.7,16.2,17.2c3.8,7.4,5.7,15.9,5.8,25.6v6.7
c0,9.9-1.9,18.5-5.7,25.9c-3.8,7.4-9.2,13.1-16.3,17.1c-7.1,4-15.3,6-24.7,6.1L221.6,148.7L221.6,148.7z M235.4,55.4v82h14.5
c10.6,0,18.9-3.3,24.8-9.9c5.9-6.6,8.9-16,8.9-28.3v-6.1c0-11.9-2.8-21.1-8.4-27.7s-13.5-9.9-23.7-10L235.4,55.4L235.4,55.4z"/>
<path class="st0" d="M627.1,148.7h-13.9l-52.7-80.6v80.6h-13.9V44.1h13.9l52.8,81v-81H627v104.6H627.1z"/>
<path class="st0" d="M900.9,100.1l-12.8,13.3v35.3h-13.8V44.1h13.8v51.7l46.5-51.7h16.7l-41.2,46.2l44.4,58.4H938L900.9,100.1z"/>
<polygon class="st0" points="423.2,61.1 455.1,148.7 469.2,148.7 429.2,44.1 417.1,44.1 377.2,148.7 391.4,148.7 "/>
<polygon class="st0" points="750.6,61.1 782.6,148.7 796.7,148.7 756.7,44.1 744.6,44.1 704.7,148.7 718.9,148.7 "/>
</g>
<path class="st0" d="M132.1,140.4c0,0-26.1,25.2-48,46.5v28.9c-2.2,1.7,77.6-75.4,77.6-75.4L84.1,59v31L132.1,140.4z"/>
<g>
<polygon class="st0" points="83.7,157.5 6.5,75.1 7.5,74.2 84.7,156.6 "/>
<polygon class="st0" points="83.7,149.8 13.6,75.2 14.6,74.3 84.6,148.9 "/>
<polygon class="st0" points="83.7,142.1 20.7,75.4 21.7,74.4 84.6,141.1 "/>
<polygon class="st0" points="83.6,134.3 27.8,75.5 28.7,74.6 84.6,133.4 "/>
<polygon class="st0" points="83.6,126.6 34.9,75.6 35.8,74.7 84.6,125.7 "/>
</g>
<g>
<polygon class="st0" points="8,75.5 7.1,74.5 83.7,0 84.6,0.9 "/>
<polygon class="st0" points="15.2,75.5 14.3,74.6 83.6,7 84.5,7.9 "/>
<polygon class="st0" points="22.4,75.6 21.4,74.7 83.6,14 84.5,14.9 "/>
<polygon class="st0" points="29.5,75.6 28.6,74.7 83.5,21 84.4,22 "/>
<polygon class="st0" points="36.7,75.7 35.7,74.8 83.5,28 84.4,29 "/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -122,4 +122,10 @@ export const Pages = {
list: "/company/list", list: "/company/list",
detail: "/company/detail/", detail: "/company/detail/",
}, },
bill: {
createBillWater: "/bill/water/create",
createBillCharge: "/bill/charge/create",
ListBillWater: "/bill/water/list",
ListBillCharge: "/bill/charge/list",
},
}; };
+192
View File
@@ -0,0 +1,192 @@
import { FC, useEffect, useRef } from 'react'
import { useGetAllCompanies } from '../company/hooks/useCompanyData'
import { useFormik } from 'formik'
import * as Yup from 'yup'
import { CreateBillType } from './types/Types'
import { useCreateBill } from './hooks/useBillData'
import Button from '../../components/Button'
import Input from '../../components/Input'
import { TickCircle } from 'iconsax-react'
import { toast } from 'react-toastify'
import { ErrorType } from '../../helpers/types'
import { Pages } from '../../config/Pages'
import { useNavigate } from 'react-router-dom'
import { CompanyItemType } from '../company/types/CompanyTypes'
import PageLoading from '../../components/PageLoading'
const CreateBill: FC = () => {
const navigate = useNavigate()
const getCompanies = useGetAllCompanies()
const createBill = useCreateBill()
const companies: CompanyItemType[] = getCompanies.data?.data?.companies ?? []
const formik = useFormik<CreateBillType>({
initialValues: {
waterRate: 0,
dueDays: 0,
values: [],
},
enableReinitialize: true,
validationSchema: Yup.object({
waterRate: Yup.number().min(0, 'نرخ آب باید عدد مثبت باشد').required('نرخ آب الزامی است'),
dueDays: Yup.number().min(0, 'تعداد روز مهلت باید عدد مثبت باشد').required('تعداد روز مهلت الزامی است'),
values: Yup.array()
.of(
Yup.object({
companyId: Yup.string().required(),
waterUsage: Yup.number().min(0, 'مصرف آب باید عدد مثبت باشد').required('مصرف آب الزامی است'),
})
)
.min(1, 'حداقل یک شرکت باید مصرف داشته باشد')
.required('اطلاعات مصرف شرکت‌ها الزامی است'),
}),
onSubmit: async (values) => {
const filteredValues = values.values.filter((v) => v.companyId && (v.waterUsage ?? 0) >= 0)
if (filteredValues.length === 0) {
toast.error('حداقل یک شرکت با مصرف معتبر وارد کنید')
return
}
await createBill.mutateAsync(
{ ...values, values: filteredValues },
{
onSuccess: () => {
toast.success('قبض آب با موفقیت ثبت شد')
navigate(Pages.company.list)
},
onError: (error: ErrorType) => {
toast.error(error.response?.data?.error?.message?.[0] ?? 'خطا در ثبت قبض')
},
}
)
},
})
const initializedRef = useRef(false)
useEffect(() => {
if (companies.length > 0 && !initializedRef.current) {
initializedRef.current = true
formik.setFieldValue(
'values',
companies.map((c) => ({ companyId: c.id, waterUsage: 0 }))
)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [companies])
if (getCompanies.isLoading) {
return <PageLoading />
}
if (companies.length === 0 && !getCompanies.isLoading) {
return (
<div className="mt-4 p-6 bg-white rounded-3xl text-center text-gray-600">
شرکتی ثبت نشده است. ابتدا شرکت اضافه کنید.
</div>
)
}
const setWaterUsage = (companyId: string, waterUsage: number) => {
const next = formik.values.values.map((v) =>
v.companyId === companyId ? { ...v, waterUsage } : v
)
formik.setFieldValue('values', next)
}
return (
<div className="mt-4">
<div className="flex justify-between items-center">
<div className="text-lg font-medium">افزودن قبض آب</div>
<Button
className="w-fit px-4"
onClick={() => formik.handleSubmit()}
isLoading={createBill.isPending}
>
<div className="flex items-center gap-2">
<TickCircle size={20} color="white" />
<span>ثبت قبض</span>
</div>
</Button>
</div>
<div className="mt-10 bg-white py-8 xl:px-10 px-4 rounded-3xl">
<div className="text-base font-medium mb-6">اطلاعات قبض</div>
<div className="rowTwoInput mt-6">
<Input
label="نرخ آب (ریال)"
name="waterRate"
type="number"
min={0}
value={formik.values.waterRate}
onChange={formik.handleChange}
error_text={formik.touched.waterRate && formik.errors.waterRate ? String(formik.errors.waterRate) : ''}
/>
<Input
label="تعداد روز مهلت پرداخت"
name="dueDays"
type="number"
min={0}
value={formik.values.dueDays}
onChange={formik.handleChange}
error_text={formik.touched.dueDays && formik.errors.dueDays ? String(formik.errors.dueDays) : ''}
/>
</div>
<div className="mt-8">
<div className="mb-4">
<span className="text-sm font-medium">مصرف آب به تفکیک شرکت</span>
<p className="text-xs text-gray-500 mt-1">مصرف آب هر شرکت را در ردیف مربوطه وارد کنید.</p>
</div>
<div className="border border-border rounded-2xl overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-gray-50">
<tr>
<th className="text-right py-3 px-4 font-medium border-b border-border">ردیف</th>
<th className="text-right py-3 px-4 font-medium border-b border-border">نام شرکت</th>
<th className="text-right py-3 px-4 font-medium border-b border-border w-48">مصرف آب</th>
</tr>
</thead>
<tbody>
{companies.map((company, index) => {
const value = formik.values.values.find((v) => v.companyId === company.id)
const usage = value?.waterUsage ?? 0
return (
<tr key={company.id} className="border-b border-border last:border-0 hover:bg-gray-50/50">
<td className="py-3 px-4 text-gray-600">{index + 1}</td>
<td className="py-3 px-4 font-medium">{company.name}</td>
<td className="py-2 px-4">
<Input
name={`usage-${company.id}`}
type="number"
min={0}
value={usage}
onChange={(e) => setWaterUsage(company.id, Number(e.target.value) || 0)}
error_text={
Array.isArray(formik.errors.values) &&
formik.errors.values[index] &&
(formik.errors.values[index] as { waterUsage?: string })?.waterUsage
? (formik.errors.values[index] as { waterUsage: string }).waterUsage
: ''
}
className="!mb-0"
/>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
{formik.touched.values && typeof formik.errors.values === 'string' && (
<div className="text-xs text-red-600 mt-2 font-medium">{formik.errors.values}</div>
)}
</div>
</div>
</div>
)
}
export default CreateBill
+8
View File
@@ -0,0 +1,8 @@
import { useMutation } from "@tanstack/react-query";
import * as api from "../service/Service";
export const useCreateBill = () => {
return useMutation({
mutationFn: api.createBill,
});
};
+7
View File
@@ -0,0 +1,7 @@
import axios from "../../../config/axios";
import { CreateBillType } from "../types/Types";
export const createBill = async (params: CreateBillType) => {
const { data } = await axios.post("/bills/water", params);
return data;
};
+8
View File
@@ -0,0 +1,8 @@
export type CreateBillType = {
waterRate: number;
dueDays: number;
values: {
companyId: string;
waterUsage: number;
}[];
};
+10 -3
View File
@@ -50,10 +50,17 @@ export const useCreateCompany = () => {
}); });
}; };
export const useGetCompanies = (page: number) => { export const useGetCompanies = (page: number, perPage?: number) => {
return useQuery({ return useQuery({
queryKey: ["companies", page], queryKey: ["companies", page, perPage],
queryFn: () => api.getCompanies(page), queryFn: () => api.getCompanies(page, perPage),
});
};
export const useGetAllCompanies = () => {
return useQuery({
queryKey: ["companies", "all"],
queryFn: () => api.getCompanies(1, 1000),
}); });
}; };
+4 -2
View File
@@ -47,8 +47,10 @@ export const createCompany = async (params: CreateCompanyType) => {
return data; return data;
}; };
export const getCompanies = async (page: number) => { export const getCompanies = async (page: number, perPage?: number) => {
const { data } = await axios.get(`/companies/list?page=${page}`); let query = `?page=${page}`;
if (perPage) query += `&perPage=${perPage}`;
const { data } = await axios.get(`/companies/list${query}`);
return data; return data;
}; };
+3
View File
@@ -55,6 +55,7 @@ import RequestDetail from '../pages/requests/Detail'
import SliderList from '../pages/slider/List' import SliderList from '../pages/slider/List'
import UpdateSlider from '../pages/slider/Update' import UpdateSlider from '../pages/slider/Update'
import CreateSlider from '../pages/slider/Create' import CreateSlider from '../pages/slider/Create'
import CreateBill from '../pages/bill/Create'
const MainRouter: FC = () => { const MainRouter: FC = () => {
const { hasSubMenu } = useSharedStore() const { hasSubMenu } = useSharedStore()
@@ -123,6 +124,8 @@ const MainRouter: FC = () => {
<Route path={Pages.sliders.create} element={<CreateSlider />} /> <Route path={Pages.sliders.create} element={<CreateSlider />} />
<Route path={Pages.sliders.list} element={<SliderList />} /> <Route path={Pages.sliders.list} element={<SliderList />} />
<Route path={Pages.sliders.detail + ':id'} element={<UpdateSlider />} /> <Route path={Pages.sliders.detail + ':id'} element={<UpdateSlider />} />
<Route path={Pages.bill.createBillWater} element={<CreateBill />} />
</Routes> </Routes>
</div> </div>
</div> </div>
+1
View File
@@ -41,6 +41,7 @@ const CompanySubMenu: FC = () => {
isActive={isActive('industries')} isActive={isActive('industries')}
link={Pages.company.industries} link={Pages.company.industries}
/> />
</div> </div>
</div> </div>
+18
View File
@@ -38,6 +38,24 @@ const ReceiptSubMenu: FC = () => {
isActive={isActive('create')} isActive={isActive('create')}
link={Pages.receipts.create} link={Pages.receipts.create}
/> />
<SubMenuItem
title={'صدور قبض آب'}
isActive={isActive('bills')}
link={Pages.bill.createBillWater}
/>
<SubMenuItem
title={'صدور شارژ'}
isActive={isActive('charge')}
link={Pages.bill.createBillCharge}
/>
{/* <SubMenuItem
title={'قبض ها'}
isActive={isActive('bills')}
link={Pages.bill.create}
/> */}
</div> </div>
</div> </div>
) )