added discount mangment

This commit is contained in:
mohamadmahdi jebeli 2025-07-20 13:30:07 +03:30
parent 9ea1edf9b8
commit 9e40be9045
26 changed files with 1852 additions and 873 deletions

307
assets/icons/empty_home.svg Normal file
View File

@ -0,0 +1,307 @@
<svg width="328" height="316" viewBox="0 0 328 316" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M310.617 312.929H28.3708V315.12H310.617V312.929Z" fill="#C8D3FB"/>
<path d="M312.653 138.071C303.26 90.9514 269.916 52.1288 225.145 34.596C123.706 -5.1659 21.9528 25.5165 2.5415 135.253C-15.9305 239.824 69.8549 202.723 144.682 283.812C209.804 354.413 339.735 290.7 313.279 141.671C313.122 140.419 312.809 139.323 312.653 138.071Z" fill="url(#paint0_linear_6390_7734)"/>
<path d="M39.6418 241.233C71.1069 253.913 92.8663 245.303 118.383 276.925C143.899 308.546 135.916 315.434 87.5439 300.249C21.1698 279.586 10.3683 229.492 39.6418 241.233Z" fill="url(#paint1_linear_6390_7734)"/>
<mask id="mask0_6390_7734" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="17" width="317" height="296">
<path d="M312.653 138.071C303.26 90.9514 269.916 52.1288 225.145 34.596C123.706 -5.1659 21.9528 25.5165 2.5415 135.253C-15.9305 239.824 69.8549 202.723 144.682 283.812C209.804 354.413 339.735 290.7 313.279 141.671C313.122 140.419 312.809 139.323 312.653 138.071Z" fill="white"/>
</mask>
<g mask="url(#mask0_6390_7734)">
<path d="M130.28 53.8501H-24.697V252.503H130.28V53.8501Z" fill="url(#paint2_linear_6390_7734)"/>
<mask id="mask1_6390_7734" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="-25" y="51" width="156" height="201">
<path d="M-24.9932 251.537L130.141 251.537L130.141 51.4753L-24.9932 51.4753L-24.9932 251.537Z" fill="white"/>
</mask>
<g mask="url(#mask1_6390_7734)">
<path d="M68.7586 207.888C68.2889 205.54 66.0973 204.758 66.7235 202.096C67.0366 200.531 67.9758 199.748 66.88 198.026C66.4104 197.244 65.4712 196.461 64.6884 195.991C65.7842 195.208 66.4104 193.487 65.7842 192.234C65.6277 191.921 65.1581 191.608 64.845 191.921C64.0623 192.704 63.4361 193.643 62.8099 194.582C62.6534 193.956 62.6534 193.33 62.4969 192.704C62.3403 192.234 62.0272 191.765 61.5576 191.765C60.6183 191.765 60.6183 192.704 60.7749 193.487C58.8964 192.234 57.1744 190.982 55.2959 189.729C54.6697 189.26 53.887 188.79 53.1043 188.321C53.4174 188.008 53.7305 187.538 53.887 187.068C54.2001 185.972 53.4174 185.19 52.3216 185.659C51.6954 185.972 51.2258 186.442 50.7561 186.912C49.6603 186.286 48.408 185.816 47.1557 185.503C47.4687 185.19 47.7818 185.033 48.0949 184.564C48.408 183.937 48.0949 183.155 47.3122 182.998C46.5295 182.842 45.7468 183.468 45.1206 183.937C44.8075 184.25 44.651 184.407 44.3379 184.72C39.9547 183.937 35.415 184.564 32.2841 188.477C32.1276 188.634 31.971 188.947 31.8145 189.103C31.5014 188.164 31.0318 187.538 30.249 186.912C30.0925 186.755 29.936 186.755 29.7794 186.755C29.4663 186.599 29.1532 186.755 29.1532 187.068C28.9967 187.225 28.9967 187.381 28.9967 187.538C29.1533 188.477 29.4663 189.416 29.936 190.199C29.6229 190.199 29.3098 190.199 28.9967 190.199C28.0575 190.199 27.5878 190.043 26.6486 190.199C25.5528 190.512 24.457 191.451 23.8308 192.547C23.6743 192.86 23.5177 193.173 23.3612 193.643C21.7957 197.713 25.0831 201.314 28.214 203.349C28.3705 203.505 28.5271 203.505 28.6836 203.349C32.9103 205.853 37.6066 209.454 42.6159 210.237C43.5552 210.393 44.4944 210.08 45.4337 210.237C45.7468 210.237 48.2515 211.019 48.5645 211.332C48.8776 211.489 49.0342 212.272 49.1907 212.585C50.13 213.994 51.3823 214.933 52.9477 215.559C57.8006 217.438 67.6628 216.185 68.7586 210.08C68.9151 209.767 68.9151 208.828 68.7586 207.888Z" fill="#D5DDFB"/>
<path d="M68.602 210.237C68.4455 210.08 68.2889 210.08 68.1324 210.08C64.2188 211.646 56.5482 215.403 53.7304 210.707C53.2608 209.924 53.4174 209.454 52.4781 208.985C52.0085 208.672 51.2258 208.672 50.5996 208.358C49.0342 207.576 48.2515 205.854 48.0949 204.132C48.0949 203.819 47.7818 203.506 47.4687 203.662C45.7468 204.288 43.8683 204.915 42.1463 204.915C39.6416 204.758 36.9804 203.193 37.2935 200.375C37.2935 200.062 36.9804 199.749 36.6673 199.905C31.0318 201.627 25.3962 198.496 23.8308 193.174C23.6743 193.487 23.5177 193.8 23.3612 194.27C21.7957 198.34 25.0831 201.94 28.214 203.975C28.3705 204.132 28.5271 204.132 28.6836 203.975C32.9103 206.48 37.6066 210.08 42.6159 210.863C43.5552 211.02 44.4944 210.707 45.4337 210.863C45.7468 210.863 48.2515 211.646 48.5645 211.959C48.8776 212.116 49.0342 212.898 49.1907 213.211C50.13 214.62 51.3823 215.559 52.9477 216.186C57.8006 218.064 67.6628 216.812 68.7586 210.707C68.7586 210.394 68.7586 210.394 68.602 210.237Z" fill="#C8D3FB"/>
<path d="M31.032 198.185L30.8754 198.029C30.8754 197.872 30.8754 197.872 30.8754 197.715C31.032 197.089 29.9362 196.776 29.7796 197.402C29.4665 199.124 29.7796 201.003 30.8754 202.412C31.1885 202.725 31.8147 202.725 31.8147 202.255C32.4408 201.003 32.1278 199.437 31.032 198.185Z" fill="#D5DDFB"/>
<path d="M44.8074 203.349C44.6509 203.193 44.4944 203.193 44.3378 203.349C44.0247 202.723 43.8682 202.253 43.7117 201.627C43.5551 201.001 42.4593 201.157 42.6158 201.94C43.0855 203.662 43.8682 205.384 44.964 206.793C45.2771 207.106 45.7467 206.95 45.9032 206.48C46.2163 205.228 45.9032 204.132 44.8074 203.349Z" fill="#D5DDFB"/>
<path d="M55.4523 208.985C54.3565 210.237 52.9476 212.585 54.6695 213.994C54.9826 214.307 55.4523 214.151 55.6088 213.681C55.9219 212.585 55.9219 211.646 55.7653 210.55C55.7653 210.55 55.7653 210.394 55.6088 210.394C55.7653 210.237 55.9219 209.924 56.0784 209.767C56.7046 209.298 55.9219 208.515 55.4523 208.985Z" fill="#D5DDFB"/>
<path d="M39.9546 189.886C38.2326 188.633 37.763 193.643 37.763 194.582C37.4499 195.208 38.0761 195.834 38.5457 195.365C39.1719 194.426 39.798 193.486 40.1111 192.39C40.2677 191.608 40.5808 190.355 39.9546 189.886Z" fill="#C8D3FB"/>
<path d="M49.0343 196.775C50.1301 195.053 50.7563 193.331 50.9129 191.296C50.9129 190.983 50.7563 190.827 50.4432 190.827C49.1909 190.514 48.5647 191.923 48.2516 192.862C47.782 194.427 47.6255 196.149 48.0951 197.715C48.2516 198.341 49.3474 198.184 49.1909 197.402C49.1909 197.245 49.0343 197.088 49.0343 196.775Z" fill="#C8D3FB"/>
<path d="M51.5391 200.689C51.0695 200.375 50.5999 200.689 50.5999 201.158C50.5999 201.158 50.5999 201.315 50.5999 201.471C50.5999 202.567 51.0695 203.506 51.8522 204.132C52.1653 204.289 52.4784 204.289 52.7915 203.976C53.4176 202.567 52.4784 201.471 51.5391 200.689Z" fill="#D5DDFB"/>
<path d="M64.3752 201.784C64.3752 200.688 63.4359 200.375 62.4967 200.688C61.714 201.001 60.9313 201.471 60.1486 202.097C59.6789 202.41 59.0528 202.567 58.5831 202.88C58.1135 203.193 58.27 203.976 58.8962 203.976C59.0527 204.132 59.3658 204.132 59.6789 203.976C61.5574 203.819 64.2187 203.976 64.3752 201.784Z" fill="#C8D3FB"/>
<path d="M-1.05936 190.043C-1.99861 188.008 -4.50329 184.877 -7.00798 185.033C-7.32106 185.033 -7.47761 185.033 -7.79069 185.19C-8.72995 185.346 -9.6692 185.816 -10.4519 186.286C-10.2954 185.972 -10.2954 185.659 -10.1388 185.346C-9.82575 184.72 -10.9215 184.407 -11.2346 185.033C-11.5477 185.659 -11.7043 186.442 -11.8608 187.225C-11.8608 187.225 -12.0173 187.225 -12.0173 187.381C-12.1739 186.599 -12.1739 185.659 -12.8001 185.19C-13.2697 184.72 -13.8959 184.72 -14.2089 185.19C-14.6786 185.816 -14.3655 186.599 -14.0524 187.225C-13.8959 187.694 -13.5828 188.164 -13.4262 188.79C-13.7393 189.103 -13.8959 189.416 -14.0524 189.729C-14.6786 190.669 -14.6786 191.608 -15.1482 192.391C-15.6178 191.921 -15.9309 191.451 -16.4005 191.138C-16.7136 190.669 -17.4963 191.138 -17.3398 191.608C-17.1833 192.234 -16.8702 193.017 -16.4005 193.643C-16.5571 193.643 -16.5571 193.8 -16.7136 193.8C-17.8094 194.269 -18.4356 194.269 -19.3749 195.208C-20.3141 196.304 -21.0968 198.026 -21.5665 199.748C-21.8795 201.157 -21.8795 202.723 -21.5665 203.975C-21.2534 205.227 -20.4707 206.167 -19.2183 206.793C-18.7487 206.949 -18.2791 207.106 -17.8094 207.106C-16.5571 207.106 -15.4613 207.419 -14.522 208.202C-14.3655 208.515 -14.2089 208.671 -13.8959 208.828C-8.10378 210.706 -7.79069 200.061 -3.72058 198.183C-3.4075 198.026 -3.4075 197.87 -3.4075 197.713C-1.37244 195.522 0.192986 193.017 -1.05936 190.043Z" fill="#D5DDFB"/>
<path d="M-1.05936 190.042C-1.99861 188.007 -4.50329 184.876 -7.00798 185.033C-7.32106 185.033 -7.47761 185.033 -7.79069 185.19C-5.28601 188.32 -4.97292 192.86 -7.79069 195.834C-8.88649 196.93 -10.765 197.4 -11.2346 198.965C-11.3912 199.591 -11.2346 200.374 -11.0781 201C-10.6085 203.349 -13.2697 203.975 -15.1482 204.288C-17.1833 204.601 -19.5314 204.288 -20.6272 202.409C-21.0968 201.627 -21.2534 200.531 -21.5665 199.591C-21.8795 201 -21.8795 202.566 -21.5665 203.818C-21.2534 205.07 -20.4707 206.01 -19.2183 206.636C-18.7487 206.792 -18.2791 206.949 -17.8094 206.949C-16.5571 206.949 -15.4613 207.262 -14.522 208.045C-14.3655 208.358 -14.2089 208.514 -13.8959 208.671C-8.10378 210.549 -7.79069 199.905 -3.72058 198.026C-3.4075 197.87 -3.4075 197.713 -3.4075 197.556C-1.37244 195.521 0.192986 193.017 -1.05936 190.042Z" fill="#C8D3FB"/>
<path d="M77.9947 148.404C78.3078 148.247 78.6209 148.09 78.7774 147.777C80.0298 146.212 78.4644 144.96 77.3686 144.177C75.9597 143.081 74.3942 142.142 72.9854 141.046C71.733 139.481 70.3241 137.915 69.2283 136.506C70.7937 133.532 71.2634 130.714 70.9503 128.209C72.0461 126.488 72.3592 124.296 71.733 122.417C71.2634 120.852 68.7587 121.322 68.9153 122.73C68.2891 121.635 67.5064 120.695 66.5671 119.756C67.3498 119.13 67.976 117.721 68.1325 116.938C68.1325 116.625 67.976 116.312 67.8194 116.312C67.0367 116.156 66.4106 116.625 65.9409 117.095L65.7844 117.251C65.6279 117.408 65.6278 117.565 65.4713 117.721C65.3148 117.878 65.1582 118.034 65.0017 118.347C61.5577 115.216 57.018 113.025 52.7913 111.616C52.6348 111.616 52.3217 111.459 52.1652 111.459C52.7913 110.364 53.1044 108.955 52.7913 107.546C52.6348 107.076 52.1652 107.076 51.8521 107.233C51.0694 107.859 50.5997 108.798 50.2867 109.737C49.9736 108.798 49.6605 107.859 49.1909 106.92C49.0343 106.607 48.8778 106.45 48.5647 106.45C48.2516 105.98 47.9385 105.511 47.4689 105.041C47.1558 104.728 46.8427 104.885 46.5296 105.198C45.9035 105.98 45.5904 106.92 45.7469 107.859C45.7469 108.172 45.7469 108.329 45.5904 108.642C43.7119 107.389 41.9899 105.98 40.1114 103.945C39.3287 103.163 38.546 102.38 37.7632 101.754C38.859 100.971 37.6067 98.3098 37.2936 97.5271C37.1371 97.0575 36.5109 97.214 36.3544 97.5271C35.7282 98.3098 35.5716 99.2491 35.4151 100.188C34.3193 99.5622 33.2235 98.936 31.9712 98.6229C26.6487 96.5878 20.7001 96.7444 15.2211 98.4664C15.3776 97.9967 15.2211 97.6836 14.908 97.3706C14.4384 96.9009 13.8122 97.214 13.4991 97.8402C13.186 98.3098 12.8729 98.936 12.5599 99.4056C11.9337 99.7187 11.3075 99.8752 10.5248 100.188C8.17666 101.284 5.98506 101.91 3.79346 102.536C3.95001 101.91 4.10655 101.284 4.26309 100.971C4.41964 100.345 4.57619 99.5622 3.95001 99.2491C3.32384 98.936 2.69767 99.4056 2.22804 99.7187C1.13224 100.658 0.662613 101.91 0.192986 103.163C-1.2159 103.319 -2.78133 103.476 -4.34676 103.632C-5.91219 103.632 -7.63415 103.945 -9.19958 104.102C-8.72995 102.85 -8.72995 101.128 -9.98229 100.345C-11.3912 99.5622 -12.9566 101.284 -13.8959 102.223C-14.9917 103.319 -15.9309 104.728 -16.7136 106.137C-20.001 107.389 -23.1319 109.111 -25.9496 111.303C-26.5758 111.772 -27.0454 112.242 -27.6716 112.555C-29.0805 110.99 -30.959 109.737 -32.9941 109.111C-34.716 108.642 -35.3422 110.99 -34.0899 111.772C-33.3072 112.868 -32.2114 113.964 -31.1156 114.747C-32.9941 115.53 -35.0291 115.843 -38.0034 115.06C-48.6483 112.399 -55.3797 115.53 -60.076 121.948C-60.076 121.635 -60.2325 121.322 -60.389 121.009C-60.5456 120.539 -61.1718 120.382 -61.3283 120.852C-61.6414 121.322 -61.7979 121.948 -61.7979 122.417C-62.111 121.948 -62.4241 121.635 -62.8937 121.322C-62.8937 121.322 -62.8937 121.322 -63.0503 121.165L-63.2068 121.009C-63.3634 120.852 -63.5199 120.852 -63.833 121.009C-64.7722 121.478 -65.2419 122.261 -65.3984 123.2C-66.1811 125.548 -65.7115 128.053 -64.6157 130.088C-64.7722 130.714 -65.0853 131.34 -65.2419 131.967C-66.3377 131.184 -67.59 130.714 -68.9989 130.558C-69.312 130.558 -69.4685 130.714 -69.4685 130.871C-69.6251 131.027 -69.6251 131.34 -69.4685 131.497C-68.6858 132.749 -67.2769 133.688 -65.868 133.845C-65.555 134.315 -65.7115 134.628 -65.868 135.097H-66.0246C-71.5036 137.602 -73.6952 140.576 -72.9125 146.682C-72.4428 149.969 -72.1298 153.726 -70.5643 156.7C-72.7559 158.735 -74.6344 161.083 -75.8868 163.432L-76.0433 163.275C-76.1999 162.649 -76.826 162.336 -77.4522 162.336C-78.7045 162.023 -79.6438 163.588 -78.8611 164.684C-78.8611 166.249 -78.7045 167.815 -77.9218 169.067C-78.8611 168.911 -79.8003 168.911 -80.7396 168.754C-81.2092 168.754 -81.3658 169.38 -81.0527 169.693C-79.9569 170.946 -78.548 171.572 -76.9826 171.728C-76.6695 173.92 -75.8868 176.112 -74.6344 177.99C-72.5994 181.591 -69.312 184.721 -65.7115 186.6C-59.2933 189.887 -52.5619 188.792 -45.674 187.539C-39.882 186.443 -35.6553 182.373 -33.7768 177.051C-29.3936 179.556 -24.2277 177.834 -22.0361 173.45C-17.3398 174.546 -12.8001 172.981 -9.51266 169.38C-7.00798 166.562 -6.85143 164.058 -5.75564 160.614C-4.65984 157.326 -5.5991 158.422 -2.46824 157.953C-0.746269 157.796 0.81916 157.796 2.38458 157.483C6.61124 156.7 9.42901 154.978 13.186 153.256C15.3776 152.317 18.5085 150.282 21.0132 152.161C21.7959 152.787 22.4221 154.822 23.0482 155.604C24.7702 157.953 27.1183 159.831 29.623 160.927C33.6931 162.805 38.7025 161.553 42.1464 164.527C47.3123 168.911 50.9128 174.233 58.4269 174.703C62.6535 174.859 65.4713 173.607 67.8194 171.259C68.9152 170.163 69.8545 168.911 70.9503 167.345C74.2377 162.649 80.8125 162.962 80.3429 155.761C80.4994 153.569 79.4036 151.065 77.9947 148.404Z" fill="#D5DDFB"/>
<path d="M61.5574 174.858C64.2187 174.389 66.2537 173.293 67.9757 171.571C67.6626 170.632 67.193 169.849 66.4103 169.066C64.5318 167.188 61.8705 166.875 59.5224 166.092C52.1649 163.587 51.8518 156.699 52.0083 149.968C52.0083 149.029 51.0691 148.403 50.1298 148.559C46.3728 149.342 42.6158 149.185 39.0153 148.246C38.8588 148.09 38.5457 147.933 38.3891 147.776C37.2933 146.681 37.9195 145.585 37.763 144.176C37.763 144.176 37.763 144.176 37.763 144.019C37.763 143.55 37.6064 143.237 37.2933 143.08C36.3541 142.297 34.7886 142.611 34.9452 144.019V144.176C34.7886 145.115 34.1625 145.428 33.3798 145.585C32.4405 145.272 31.8143 144.646 31.1882 143.863C30.562 143.237 30.2489 142.611 30.0924 141.671C30.0924 141.045 30.0924 140.575 29.9358 139.949C29.9358 139.793 29.7793 139.636 29.6227 139.636C29.6227 139.167 28.84 138.854 28.5269 139.323C27.9008 140.262 27.9008 141.202 28.0573 142.141C27.9008 141.984 27.5877 141.671 27.4311 141.515C26.1788 140.106 25.2395 138.384 23.5176 137.288C20.0736 135.253 16.4731 134.94 13.4988 131.496C13.0292 130.87 11.9334 131.026 11.4638 131.496C9.58527 133.375 7.39367 135.41 4.88898 137.288C3.16702 137.288 1.75813 136.818 0.818878 135.41C-0.120377 133.844 -2.31198 135.096 -1.68581 136.662C-1.68581 136.975 -1.68581 137.445 -1.21618 137.758C0.975418 139.636 -3.0947 141.358 -4.34704 141.828C-4.66013 141.828 -4.81666 141.984 -4.97321 142.141C-8.41714 142.611 -11.8611 141.828 -14.8354 138.697C-15.4616 138.071 -16.2443 138.227 -16.8705 138.697C-20.784 141.984 -20.6275 146.681 -23.2887 150.438C-25.4803 152.16 -33.1509 149.812 -32.3682 151.533C-31.742 152.786 -30.6462 153.569 -29.5504 154.195C-30.6462 154.508 -31.5855 154.821 -32.5247 155.291C-36.7514 157.326 -38.3168 160.77 -43.9523 157.952C-44.7351 157.169 -45.3612 156.386 -45.8309 155.291C-46.6136 153.569 -49.1183 155.134 -48.3355 156.699C-47.8659 157.795 -47.2397 158.734 -46.457 159.517C-45.9874 167.188 -46.3005 175.798 -54.2842 179.868C-61.0155 183.155 -68.2165 181.433 -74.7913 178.459C-72.7562 182.059 -69.4688 185.19 -65.8683 187.069C-61.172 189.573 -56.1627 189.573 -51.1533 188.947C-51.3099 189.26 -51.4664 189.573 -51.6229 190.043C-51.7795 190.513 -51.3099 190.826 -50.8402 190.669C-50.6837 190.826 -50.5271 190.826 -50.2141 190.669C-49.1183 190.2 -48.3355 189.417 -47.7094 188.321C-47.0832 188.165 -46.457 188.165 -45.6743 188.008C-43.1696 187.538 -41.1346 186.599 -39.2561 185.19C-39.0995 185.66 -38.6299 186.129 -38.0037 185.973C-37.8472 185.973 -37.6906 185.816 -37.6906 185.816C-37.3776 185.816 -37.221 185.66 -37.221 185.347C-37.221 184.721 -37.221 183.938 -37.221 183.312C-35.8121 181.746 -34.5598 179.711 -33.9336 177.676C-29.5504 180.181 -24.3845 178.459 -22.1929 174.076C-20.784 174.389 -19.5317 174.389 -18.2793 174.389C-18.2793 174.702 -18.1228 175.171 -18.1228 175.485C-17.9663 175.798 -17.8097 175.954 -17.4966 175.798C-17.3401 175.954 -17.027 175.954 -16.8705 175.798C-16.4008 175.171 -16.0877 174.545 -15.9312 173.919C-13.7396 173.293 -11.548 171.884 -9.82603 170.006C-7.32135 167.188 -7.1648 164.683 -6.069 161.239C-4.97321 157.952 -5.91246 159.048 -2.78161 158.578C-1.05964 158.421 0.505791 158.421 2.07122 158.108C4.10628 157.795 5.98479 157.169 7.70676 156.386C8.33292 156.699 8.9591 157.012 9.58527 157.169C9.89835 157.326 10.2114 157.012 10.2114 156.699C10.2114 156.23 10.0549 155.917 9.58527 155.604C9.58527 155.604 9.42873 155.604 9.27218 155.447C9.74181 155.134 10.368 154.977 10.8376 154.664C10.8376 154.821 10.9942 154.977 11.1507 155.134C11.4638 155.604 11.9334 155.447 12.09 154.977C12.2465 154.664 12.2465 154.195 12.403 153.882C12.5596 153.882 12.7161 153.725 12.7161 153.725C14.9077 152.786 18.0386 150.751 20.5433 152.629C21.326 153.255 21.9521 155.291 22.5783 156.073C24.1437 158.108 26.1788 159.83 28.3704 160.926C28.84 162.022 29.6227 162.961 30.2489 163.9C30.562 164.213 31.1882 164.057 31.1882 163.587C31.3447 162.961 31.1882 162.491 31.1882 161.865C32.7536 162.178 34.319 162.335 35.8845 162.648C35.8845 163.587 36.041 164.37 36.8237 164.996C37.1368 165.309 37.6064 165.153 37.763 164.683C37.9195 164.057 37.9195 163.431 37.763 162.961C39.1718 163.274 40.5807 163.744 41.8331 164.84C46.999 169.066 50.5995 174.389 57.8004 175.015C58.8962 175.798 60.1486 176.267 61.4009 176.424C61.8705 176.58 62.3402 175.954 61.8705 175.485C62.1836 175.328 61.8705 175.015 61.5574 174.858Z" fill="#C8D3FB"/>
<path d="M20.387 134.315C20.387 134.158 20.2304 134.158 20.0739 134.158C20.2304 133.532 19.2912 133.219 18.9781 133.845C18.5085 135.411 18.1954 137.133 19.2912 138.385C19.4477 138.698 19.7608 138.855 20.0739 139.011C20.387 139.168 20.8566 139.011 20.8566 138.698C21.1697 137.133 21.0132 135.724 20.387 134.315Z" fill="#D5DDFB"/>
<path d="M8.01996 133.846C7.55033 133.689 7.08071 134.159 7.23725 134.628C7.70688 135.568 8.64613 136.35 9.58539 136.663C10.055 136.82 10.3681 136.35 10.2116 136.037C10.055 134.785 9.11576 134.002 8.01996 133.846Z" fill="#D5DDFB"/>
<path d="M1.44544 140.263C0.506179 138.854 -0.746161 137.758 -2.15505 136.819C-2.78122 136.506 -3.25085 137.445 -2.78122 137.758C-2.31159 138.071 -1.84196 138.541 -1.37233 138.854H-1.52887C-1.84196 138.854 -2.15505 139.01 -2.15505 139.324C-2.15505 139.48 -2.15505 139.48 -2.15505 139.637C-2.31159 139.637 -2.46813 139.637 -2.62467 139.793V139.637C-2.62467 139.01 -3.56393 138.854 -3.72047 139.48C-4.34664 141.359 -4.34664 143.707 -2.46813 144.803C-2.15505 144.959 -1.68542 144.803 -1.68542 144.489C-1.21579 143.237 -1.05925 141.985 -1.05925 140.732C-0.433074 141.046 0.349638 141.202 0.975809 141.046C1.44544 141.046 1.60198 140.576 1.44544 140.263Z" fill="#D5DDFB"/>
<path d="M44.1814 148.248C44.0249 147.778 43.5552 147.465 43.2422 147.935C42.3029 149.187 41.2071 151.066 42.616 152.475C42.9291 152.788 43.3987 152.631 43.5552 152.162C44.0249 151.066 44.1814 149.97 44.4945 148.874C44.4945 148.561 44.338 148.248 44.1814 148.248Z" fill="#D5DDFB"/>
<path d="M53.1048 156.074C52.9482 155.917 52.9482 155.917 52.6351 155.917C51.8524 155.917 51.2263 156.23 50.7566 157.013C50.4436 157.639 50.6001 158.422 51.0697 158.891C51.2263 159.048 51.6959 159.048 51.8524 158.891C52.4786 158.265 52.9482 157.639 53.4179 157.013C53.5744 156.387 53.4179 156.074 53.1048 156.074Z" fill="#D5DDFB"/>
<path d="M58.8965 164.214C58.74 164.057 58.5834 163.901 58.4269 163.901C58.2703 162.961 58.1138 162.022 57.9573 161.239C57.8007 160.613 56.7049 160.457 56.8615 161.239C57.018 162.805 57.3311 164.37 57.8007 165.936C58.1138 166.875 58.4269 167.501 59.3661 167.971C59.6792 168.127 60.1488 167.814 59.9923 167.501C59.8358 166.249 59.5227 165.153 58.8965 164.214Z" fill="#D5DDFB"/>
<path d="M3.63698 117.095C3.48044 116.312 3.01081 113.807 2.07156 113.651C0.975758 113.494 0.662671 115.373 0.662671 115.999C0.506128 117.564 0.819217 119.13 1.60193 120.382C1.60193 120.539 1.60193 120.695 1.60193 120.695C1.60193 121.165 2.2281 121.478 2.69772 121.008C3.63698 120.069 3.95007 118.66 3.63698 117.095Z" fill="#C8D3FB"/>
<path d="M14.7513 112.712C14.7513 112.399 14.4383 112.086 14.1252 112.242C12.0901 112.712 10.3681 114.121 9.74196 116.156L9.58542 116.312C9.42888 116.469 9.42888 116.626 9.58542 116.782C9.58542 117.252 10.2116 117.408 10.5247 117.095C12.7163 117.095 14.7513 115.217 14.7513 112.712Z" fill="#C8D3FB"/>
<path d="M28.9971 123.514C28.684 123.201 28.2144 123.201 28.0578 123.514C26.962 124.923 26.6489 126.645 27.1186 128.367C27.1186 128.367 27.1186 128.523 27.2751 128.523C27.4317 129.15 27.5882 129.776 28.2144 130.245C28.5274 130.402 28.9971 130.245 28.9971 129.932C29.7798 127.897 30.2494 125.549 28.9971 123.514Z" fill="#C8D3FB"/>
<path d="M44.338 113.338C43.2422 113.338 41.6767 113.495 40.5809 113.965C39.7982 114.278 39.1721 114.904 38.7024 115.687C38.3893 116 38.0763 116.469 38.2328 116.939C38.5459 119.287 42.7725 116.782 43.7118 116.313C44.338 116 45.1207 115.373 45.2772 114.591C45.5903 113.808 45.1207 113.338 44.338 113.338Z" fill="#C8D3FB"/>
<path d="M56.2355 127.584C54.67 126.801 52.9481 126.331 51.2261 126.488C50.2868 126.488 49.9738 127.427 50.2868 128.053C50.2868 128.21 50.4434 128.523 50.5999 128.68C52.1653 129.932 54.2004 130.402 56.0789 129.619C56.8616 129.306 57.1747 128.053 56.2355 127.584Z" fill="#C8D3FB"/>
<path d="M61.0884 142.455C59.9926 141.829 59.3664 142.925 59.0534 143.707C58.7403 144.647 58.5837 145.586 58.5837 146.525C58.5837 147.621 59.8361 147.934 60.4622 147.308C60.6188 147.308 60.7753 147.151 60.7753 146.995C61.245 146.369 61.7146 145.586 61.8711 144.803C62.0277 144.021 62.0277 142.925 61.0884 142.455Z" fill="#C8D3FB"/>
<path d="M68.7591 152.787C68.133 152.005 67.0371 151.535 65.9414 151.535C65.3152 151.535 64.8456 152.005 64.8456 152.631C64.8456 152.787 64.8456 152.787 64.8456 152.944C64.689 153.57 65.0021 154.04 65.6283 154.353C66.5675 154.666 67.3502 154.666 68.2895 154.509C69.2287 154.509 69.2288 153.257 68.7591 152.787Z" fill="#D5DDFB"/>
<path d="M56.8612 199.279C50.5995 200.844 44.3378 201.783 37.9195 201.783C39.1719 200.218 39.798 193.8 38.8588 195.365C36.6672 198.965 34.006 202.253 31.0317 204.914C31.6578 203.036 28.527 198.026 28.6835 199.748C29.1531 202.879 27.9008 206.01 25.5527 208.045C25.083 208.358 19.9171 210.863 16.9428 211.958C17.0994 210.08 17.2559 209.61 17.4124 207.732C18.1952 198.026 16.9428 188.79 16.4732 179.241C16.0036 168.44 18.9779 156.699 19.9171 144.489C20.0737 142.61 12.5596 171.257 11.6204 182.998C10.9942 180.963 10.368 178.928 9.42876 177.049C7.86334 173.605 5.82828 170.631 3.63668 167.657C3.63668 167.5 0.505824 151.846 0.662367 153.725C0.81891 157.168 0.975455 160.769 0.818913 164.213C-1.68577 161.239 -10.2956 156.542 -9.04328 157.795C-1.99886 164.996 5.35865 172.666 8.4895 182.528C10.0549 187.694 10.5246 193.33 10.5246 198.809C4.10631 198.652 -1.21614 198.026 -8.57365 194.113C-3.2512 198.965 3.3236 201.627 10.368 201.783C10.2115 205.384 9.89839 208.984 9.42876 212.585C7.39371 230.587 7.08062 260.8 7.23716 279.585C6.92408 280.368 7.08062 281.15 8.17642 281.464C10.9942 282.09 13.4989 282.403 16.4732 282.246C17.4124 282.246 18.0386 281.307 17.8821 280.368C15.6905 263.305 14.4381 233.561 16.4732 216.342C23.8307 213.994 30.4055 209.923 35.5714 204.288C35.7279 204.444 36.041 204.444 36.1976 204.444C43.5551 204.914 58.7397 198.809 56.8612 199.279Z" fill="#C8D3FB"/>
<path d="M56.2351 147.306C58.5833 157.481 64.5319 164.682 74.081 170.318C80.1862 173.918 87.7002 176.893 96.6232 179.554C97.2493 179.711 101.633 179.711 102.572 179.554C128.714 174.701 141.551 152.316 143.273 132.904C144.056 123.355 142.49 113.806 138.733 104.726C135.289 96.2732 129.967 88.446 122.922 81.5581C116.974 75.7661 106.485 65.5908 95.6839 67.9389C90.0484 69.1913 86.2913 73.4179 82.8474 76.7053C79.0904 80.6189 75.4899 84.689 72.359 88.9157C59.0529 106.292 51.6954 127.112 56.2351 147.306Z" fill="#D5DDFB"/>
<path d="M73.9241 170.319C80.0292 173.919 87.5433 176.893 96.4662 179.555C97.0924 179.711 101.476 179.711 102.415 179.555C128.557 174.702 141.394 152.316 143.116 132.905C143.899 123.356 142.333 113.807 138.576 104.727C139.046 112.398 137.637 120.538 136.072 128.052C134.35 136.036 131.375 144.019 125.114 150.594C118.852 157.325 109.459 161.239 100.067 164.683C91.6134 167.657 83.0035 169.849 73.9241 170.319Z" fill="#C8D3FB"/>
<path d="M129.341 105.822C129.497 105.979 129.497 105.979 129.654 105.979C129.81 106.135 130.28 106.292 130.593 106.135C133.254 105.352 135.759 104.57 137.011 102.378C138.577 99.7168 137.324 96.586 136.698 93.9248C136.541 93.4551 135.915 93.142 135.289 93.4551C131.532 96.4294 125.584 101.282 129.341 105.822Z" fill="#D5DDFB"/>
<path d="M122.296 92.9861C122.453 93.1426 122.453 93.1426 122.609 93.1426C122.766 93.2992 123.236 93.4557 123.549 93.2992C126.21 92.5164 128.715 91.7337 129.967 89.5421C131.532 86.8809 130.28 83.75 129.654 81.0888C129.497 80.6192 128.871 80.3061 128.245 80.6192C124.331 83.5935 118.383 88.4463 122.296 92.9861Z" fill="#D5DDFB"/>
<path d="M114.469 86.4114C114.625 86.5679 114.625 86.5679 114.782 86.5679C114.939 86.7245 115.408 86.881 115.721 86.7245C118.383 85.9417 120.887 85.159 122.14 82.9674C123.705 80.3062 122.453 77.1753 121.826 74.5141C121.67 74.0445 121.044 73.7314 120.418 74.0445C116.661 77.1753 110.712 81.8716 114.469 86.4114Z" fill="#D5DDFB"/>
<path d="M106.016 78.4268C106.173 78.5834 106.329 78.5834 106.329 78.5834C106.642 78.7399 106.955 78.8965 107.268 78.7399C109.773 77.6441 112.121 76.5483 113.06 74.3567C114.156 71.539 112.434 68.5646 111.338 66.06C111.182 65.5903 110.399 65.4338 109.93 65.7469C106.486 69.0343 101.476 74.3567 106.016 78.4268Z" fill="#D5DDFB"/>
<path d="M63.5922 93.6119C63.1225 93.2988 62.3398 93.6119 62.1833 94.0815C61.5571 96.7427 60.3048 99.8736 61.8702 102.535C63.1225 104.726 65.7838 105.509 68.2884 106.292C68.7581 106.448 69.0712 106.292 69.2277 106.135C69.3842 106.135 69.5408 105.979 69.5408 105.979C73.4544 101.282 67.6623 96.4296 63.5922 93.6119Z" fill="#D5DDFB"/>
<path d="M70.7931 85.4717C70.3235 85.1586 69.5407 85.4717 69.3842 85.9414C68.758 88.6026 67.5057 91.7334 69.0711 94.3947C70.3235 96.5863 72.9847 97.369 75.4894 98.1517C75.959 98.3082 76.2721 98.1517 76.4286 97.9952C76.5852 97.9952 76.7417 97.8386 76.7417 97.8386C80.6553 93.1423 74.8632 88.446 70.7931 85.4717Z" fill="#C8D3FB"/>
<path d="M78.4637 74.2007C77.9941 73.8876 77.2114 74.2007 77.0549 74.6704C76.4287 77.3316 75.1763 80.4624 76.7418 83.1237C77.9941 85.3153 80.6553 86.098 83.16 86.8807C83.6297 87.0372 83.9427 86.8807 84.0993 86.7242C84.2558 86.7242 84.4124 86.5676 84.4124 86.5676C88.3259 81.8713 82.5339 77.175 78.4637 74.2007Z" fill="#D5DDFB"/>
<path d="M89.1088 65.747C88.6391 65.2773 87.8564 65.5904 87.6999 66.06C86.6041 68.7213 84.8821 71.539 85.9779 74.3568C86.9172 76.705 89.2653 77.6442 91.77 78.74C92.0831 78.8966 92.5527 78.8966 92.7092 78.5835C92.8658 78.5835 93.0223 78.5835 93.0223 78.4269C97.7186 74.3568 92.5527 69.0344 89.1088 65.747Z" fill="#D5DDFB"/>
<path d="M97.7186 72.1661C97.8751 72.3226 98.0317 72.3226 98.1882 72.3226C98.5013 72.4792 98.8144 72.4792 99.1275 72.3226C101.319 70.9137 103.511 69.5049 103.824 67.1567C104.293 64.3389 101.945 61.5212 100.223 59.173C99.9102 58.7034 99.1275 58.7034 98.8144 59.173C95.9966 62.7735 92.2396 68.7221 97.7186 72.1661Z" fill="#D5DDFB"/>
<path d="M120.417 149.968C120.417 150.124 120.417 150.281 120.417 150.281C120.417 150.594 120.574 150.907 120.887 150.907C123.548 151.69 126.21 152.472 128.871 151.533C132.315 150.437 134.037 147.463 135.759 145.115C136.072 144.645 135.759 144.019 135.132 144.019C129.81 144.176 121.357 144.645 120.417 149.968Z" fill="#C8D3FB"/>
<path d="M108.833 154.352C108.677 154.509 108.677 154.509 108.677 154.665C108.52 154.822 108.52 155.135 108.833 155.448C110.712 157.013 112.59 158.735 115.564 158.892C119.165 159.048 122.452 157.17 125.427 155.604C125.896 155.291 126.053 154.665 125.427 154.509C120.574 152.63 112.903 149.969 108.833 154.352Z" fill="#D5DDFB"/>
<path d="M96.3097 161.552C96.1531 161.708 96.1531 161.708 96.1531 161.865C95.9966 162.021 95.9966 162.335 96.3097 162.648C98.1882 164.213 100.067 165.935 103.041 166.092C106.641 166.248 109.929 164.37 112.903 162.804C113.373 162.491 113.529 161.865 112.903 161.708C108.207 159.83 100.38 157.169 96.3097 161.552Z" fill="#D5DDFB"/>
<path d="M126.053 138.853C126.053 139.01 126.053 139.166 126.21 139.166C126.21 139.479 126.523 139.636 126.836 139.793C129.653 140.106 132.315 140.419 134.819 139.166C137.794 137.444 138.733 134.314 139.985 131.809C140.142 131.339 139.672 130.87 139.046 130.87C133.88 131.652 125.74 133.374 126.053 138.853Z" fill="#C8D3FB"/>
<path d="M108.364 173.448C108.207 173.448 108.207 173.605 108.207 173.605C108.051 173.761 107.894 173.918 108.051 174.231C109.147 175.796 110.086 177.205 112.278 177.831C114.939 178.457 117.913 177.518 120.418 176.892C120.887 176.736 121.044 176.266 120.731 176.109C117.443 173.761 112.434 170.63 108.364 173.448Z" fill="#D5DDFB"/>
<path d="M56.078 107.544C55.4518 107.231 54.8257 107.7 54.8257 108.17C54.9822 110.988 54.6691 114.119 56.8607 116.467C58.7392 118.345 61.4005 118.658 64.2182 118.971C64.6879 118.971 65.001 118.815 65.1575 118.658C65.314 118.658 65.314 118.502 65.4706 118.345C67.9753 113.179 60.7743 109.735 56.078 107.544Z" fill="#C8D3FB"/>
<path d="M46.2158 118.972C45.5896 118.972 45.2765 119.598 45.5896 120.067C47.3116 122.416 49.1901 125.39 52.4775 126.486C55.2953 127.425 57.8 126.642 60.4612 125.86C60.9308 125.703 61.0874 125.39 60.9308 125.233C60.9308 125.077 61.0874 125.077 60.9308 124.92C60.1481 119.441 51.6948 118.972 46.2158 118.972Z" fill="#C8D3FB"/>
<path d="M49.6601 154.194C49.0339 154.351 48.8774 154.977 49.347 155.29C51.6952 157.325 54.1999 159.986 57.8003 160.456C60.7747 160.926 63.1228 159.673 65.4709 158.578C65.784 158.421 65.9406 158.108 65.784 157.795C65.784 157.638 65.784 157.638 65.784 157.482C63.2793 152.316 54.9826 153.255 49.6601 154.194Z" fill="#D5DDFB"/>
<path d="M63.1228 164.995C62.4966 165.151 62.3401 165.778 62.8097 166.091C65.1578 168.126 67.6625 170.787 71.263 171.257C74.2373 171.726 76.5855 170.474 78.9336 169.378C79.2467 169.222 79.4032 168.908 79.2467 168.595C79.2467 168.439 79.2467 168.439 79.2467 168.282C76.8985 163.273 68.4452 164.212 63.1228 164.995Z" fill="#D5DDFB"/>
<path d="M73.1416 172.354C72.5154 172.51 72.3589 173.136 72.8285 173.449C75.1766 175.484 77.6813 178.146 81.2818 178.615C84.2561 179.085 86.6042 177.833 88.9524 176.737C89.2655 176.58 89.422 176.267 89.2655 175.954C89.2655 175.797 89.2655 175.797 89.2655 175.641C86.9173 170.475 78.464 171.414 73.1416 172.354Z" fill="#C8D3FB"/>
<path d="M85.5083 179.243C85.1952 179.399 85.3518 179.869 85.6648 179.869C87.6999 180.495 90.048 181.278 92.3962 180.808C94.2747 180.338 95.0574 179.243 95.9967 177.99C96.1532 177.834 95.9967 177.677 95.8401 177.521C95.8401 177.521 95.8401 177.364 95.6836 177.364C92.5527 175.016 88.1695 177.521 85.5083 179.243Z" fill="#D5DDFB"/>
<path d="M110.086 179.243C110.399 179.399 110.242 179.869 109.929 179.869C108.207 180.495 106.172 181.278 104.293 180.808C102.728 180.338 101.945 179.243 101.163 177.99C101.006 177.834 101.163 177.677 101.163 177.521C101.163 177.521 101.163 177.364 101.319 177.364C104.137 175.016 107.737 177.521 110.086 179.243Z" fill="#D5DDFB"/>
<path d="M51.5387 131.181C50.9125 131.025 50.4429 131.651 50.5994 131.964C51.5387 134.625 52.3214 137.756 55.2957 139.635C57.6439 141.044 60.4616 140.887 63.2794 140.574C63.749 140.574 63.9056 140.261 64.0621 140.104C64.2187 139.948 64.2187 139.948 64.2187 139.791C64.8448 134.312 56.8612 132.277 51.5387 131.181Z" fill="#C8D3FB"/>
<path d="M51.5387 140.106C50.9125 139.95 50.4429 140.576 50.5994 140.889C51.5387 143.55 52.3214 146.681 55.2957 148.56C57.6439 149.968 60.4616 149.812 63.2794 149.499C63.749 149.499 63.9056 149.186 64.0621 149.029C64.2187 148.873 64.2187 148.873 64.2187 148.716C64.8448 143.237 56.8612 141.202 51.5387 140.106Z" fill="#D5DDFB"/>
<path d="M114.626 166.874C114.469 167.031 114.469 167.031 114.469 167.188C114.312 167.344 114.312 167.657 114.469 167.97C116.347 169.692 118.226 171.258 121.2 171.414C124.801 171.571 128.088 169.692 131.063 168.283C131.532 167.97 131.689 167.344 131.063 167.188C126.523 165.152 118.852 162.491 114.626 166.874Z" fill="#D5DDFB"/>
<path d="M121.514 162.491C121.514 162.648 121.357 162.804 121.514 162.804C121.357 163.117 121.357 163.43 121.827 163.587C124.175 164.996 126.366 166.248 129.341 165.935C132.941 165.622 135.759 163.274 138.264 161.395C138.733 161.082 138.577 160.456 137.951 160.299C132.785 159.204 124.488 157.638 121.514 162.491Z" fill="#D5DDFB"/>
<path d="M89.4221 82.6543C89.5786 82.6543 89.5786 82.6543 89.7352 82.6543C89.8917 82.8108 90.2048 82.8108 90.3614 82.6543C91.6137 81.5585 92.866 80.6192 92.866 79.0538C92.866 77.1753 91.1441 75.6099 89.8917 74.3575C89.7352 74.201 89.109 74.0444 88.9525 74.3575C87.387 76.8622 85.6651 80.7758 89.4221 82.6543Z" fill="#D5DDFB"/>
<path d="M69.2285 124.295C69.385 124.295 69.385 124.295 69.5415 124.295C69.6981 124.295 70.0112 124.295 70.1677 124.138C70.9504 122.886 71.8897 121.634 71.2635 120.225C70.6373 118.503 68.4457 117.407 66.7238 116.311C66.4107 116.155 65.9411 116.155 65.9411 116.468C65.4714 119.129 65.0018 123.356 69.2285 124.295Z" fill="#D5DDFB"/>
<path d="M88.7954 132.747C88.9519 132.747 88.9519 132.747 89.1085 132.904C89.265 133.06 89.5781 133.06 89.7346 132.904C91.1435 131.964 92.5524 131.182 92.7089 129.616C93.022 127.738 91.6131 126.016 90.5173 124.607C90.3608 124.294 89.8912 124.294 89.5781 124.607C88.0127 126.798 85.508 130.399 88.7954 132.747Z" fill="#C8D3FB"/>
<path d="M112.121 112.553C112.121 112.71 112.277 112.71 112.434 112.866C112.59 113.179 112.904 113.336 113.373 113.179C116.191 112.866 118.852 112.553 120.731 110.675C122.922 108.327 122.766 105.196 122.766 102.378C122.766 101.908 122.14 101.439 121.513 101.752C116.974 103.943 109.773 107.544 112.121 112.553Z" fill="#D5DDFB"/>
<path d="M90.2044 107.858C90.3609 107.858 90.5175 107.858 90.674 107.858C90.9871 107.858 91.4567 107.858 91.7698 107.545C93.6483 105.666 95.6834 103.945 95.2137 101.753C94.7441 99.0917 91.1436 97.3697 88.4824 95.6477C88.0128 95.3347 87.0735 95.4912 86.917 95.9608C85.195 100.031 83.0034 106.136 90.2044 107.858Z" fill="#C8D3FB"/>
<path d="M108.52 87.1937C108.52 87.3502 108.677 87.3502 108.833 87.5068C108.99 87.6633 109.303 87.8199 109.616 87.8199C111.964 87.8199 114.469 87.8199 115.721 86.411C117.443 84.8455 116.66 82.1843 116.347 79.9927C116.347 79.6796 115.721 79.21 115.251 79.3665C111.494 80.7754 105.702 82.967 108.52 87.1937Z" fill="#D5DDFB"/>
<path d="M109.46 139.01C109.46 139.166 109.616 139.166 109.773 139.323C109.929 139.479 110.242 139.636 110.555 139.636C112.904 139.636 115.408 139.636 116.661 138.227C118.383 136.661 117.6 134 117.287 131.809C117.287 131.496 116.661 131.026 116.191 131.182C112.434 132.435 106.642 134.783 109.46 139.01Z" fill="#D5DDFB"/>
<path d="M106.954 179.554C104.763 182.997 104.45 186.598 105.702 191.138C106.485 193.955 107.894 197.086 109.616 200.53C109.772 200.843 111.024 202.096 111.338 202.409C120.26 209.297 130.279 207.418 136.228 202.878C139.046 200.687 141.394 197.712 142.803 194.112C144.211 190.825 144.838 187.068 144.681 183.154C144.525 179.867 144.368 173.918 140.611 171.1C138.576 169.691 136.384 169.535 134.506 169.378C132.314 169.222 130.123 169.222 128.088 169.222C119.321 169.848 111.337 172.822 106.954 179.554Z" fill="#D5DDFB"/>
<path d="M105.702 191.138C106.484 193.956 107.893 197.087 109.615 200.531C109.772 200.844 111.024 202.096 111.337 202.409C120.26 209.297 130.279 207.419 136.227 202.879C139.045 200.687 141.393 197.713 142.802 194.113C140.767 196.304 138.106 198.026 135.601 199.435C132.784 201 129.809 202.096 126.052 201.94C122.295 201.783 118.538 199.905 114.938 197.87C111.65 195.834 108.519 193.799 105.702 191.138Z" fill="#C8D3FB"/>
<path d="M122.452 167.342C122.452 167.029 121.983 166.716 121.826 166.873C120.417 167.655 118.852 168.438 118.226 170.16C117.756 171.569 118.382 173.134 119.008 174.543C119.165 174.7 119.322 174.856 119.478 174.856H119.635C122.922 174.856 122.765 170.317 122.452 167.342Z" fill="#D5DDFB"/>
<path d="M114.312 169.065C114.155 168.751 113.685 168.595 113.529 168.908C112.433 170.004 111.024 171.256 111.024 173.135C111.024 174.7 112.12 175.796 113.059 177.205C113.216 177.361 113.372 177.518 113.529 177.361H113.685C116.973 176.109 115.407 171.726 114.312 169.065Z" fill="#D5DDFB"/>
<path d="M124.33 202.567C124.487 202.88 124.174 203.193 123.861 203.193C122.295 203.036 120.417 202.88 119.321 201.471C118.382 200.375 118.225 198.809 118.225 197.401C118.225 197.088 118.382 197.088 118.538 196.931L118.695 196.774C121.512 195.992 123.234 199.905 124.33 202.567Z" fill="#D5DDFB"/>
<path d="M114.625 202.409C114.468 202.409 114.468 202.409 114.312 202.566C114.155 202.566 113.842 202.722 113.842 203.035C113.529 204.444 113.373 206.01 114.312 207.106C115.564 208.514 118.069 208.671 120.104 208.984C120.417 208.984 120.887 208.671 120.73 208.358C120.104 205.54 118.852 201.47 114.625 202.409Z" fill="#C8D3FB"/>
<path d="M126.053 204.131C125.896 204.131 125.896 204.287 125.896 204.287C125.74 204.444 125.583 204.6 125.74 204.913C126.21 206.322 126.523 207.731 127.932 208.357C129.653 208.984 132.002 208.044 133.88 207.418C134.193 207.262 134.506 206.792 134.193 206.635C132.471 204.6 129.497 201.626 126.053 204.131Z" fill="#C8D3FB"/>
<path d="M121.982 181.119L122.139 181.275C122.295 181.432 122.452 181.432 122.765 181.432C124.174 180.962 125.426 180.492 125.896 179.24C126.365 177.675 125.426 175.796 124.643 174.074C124.487 173.761 124.017 173.605 123.861 173.761C121.982 175.483 119.321 178.144 121.982 181.119Z" fill="#C8D3FB"/>
<path d="M112.589 187.693C112.746 187.693 112.746 187.849 112.903 187.849C113.059 188.006 113.216 188.006 113.529 187.849C114.781 187.223 116.033 186.44 116.19 185.188C116.346 183.466 115.094 181.9 113.998 180.335C113.842 180.022 113.372 180.022 113.216 180.179C111.65 182.057 109.459 185.344 112.589 187.693Z" fill="#C8D3FB"/>
<path d="M124.8 190.198C124.8 190.355 124.643 190.355 124.643 190.511C124.486 190.668 124.486 190.981 124.643 191.138C125.426 192.39 126.052 193.642 127.461 193.642C129.183 193.799 130.748 192.39 132.157 191.294C132.47 191.138 132.47 190.668 132.314 190.511C130.279 188.946 126.835 186.911 124.8 190.198Z" fill="#D5DDFB"/>
<path d="M102.102 154.194C102.102 154.194 100.85 272.384 104.763 316.685H91.4573C91.4573 316.685 101.163 165.152 102.102 154.194Z" fill="#C8D3FB"/>
<path d="M100.38 182.685C100.38 182.685 89.5782 168.283 86.917 162.491C86.917 162.491 97.7184 183.938 99.7535 191.452L100.38 182.685Z" fill="#C8D3FB"/>
<path d="M100.223 208.357C100.223 208.357 107.894 201.156 116.19 193.799C116.19 193.799 105.702 209.61 100.849 217.124L100.223 208.357Z" fill="#C8D3FB"/>
<path d="M100.693 176.423C100.693 176.423 106.955 167.97 108.52 164.526C108.52 164.526 102.259 177.206 101.006 181.746L100.693 176.423Z" fill="#C8D3FB"/>
</g>
<path opacity="0.31" d="M-24.9932 251.537L130.141 251.537L130.141 51.4753L-24.9932 51.4753L-24.9932 251.537Z" fill="white"/>
<path opacity="0.6" d="M76.2729 247.963H92.5533L23.518 53.8501H7.23755L76.2729 247.963Z" fill="white"/>
<path opacity="0.6" d="M104.92 247.963H113.061L44.0252 53.8501H36.0415L104.92 247.963Z" fill="white"/>
<path opacity="0.6" d="M26.0229 247.964H34.1631L-22.975 74.8271L-24.8535 86.0982L26.0229 247.964Z" fill="white"/>
<path d="M128.117 254.177H132.656L132.656 49.2627H128.117L128.117 254.177Z" fill="white"/>
<path d="M76.3658 253.237H80.9055L80.9055 50.3578H76.3658L76.3658 253.237Z" fill="white"/>
<path d="M-27.1785 49.3357V53.8755L132.495 53.8755V49.3357L-27.1785 49.3357Z" fill="white"/>
<path d="M-27.1482 249.367V253.907H132.525V249.367H-27.1482Z" fill="white"/>
<path d="M24.6155 253.237H29.1553L29.1553 50.3578H24.6155L24.6155 253.237Z" fill="white"/>
<path d="M132.628 149.499H-27.0452V154.039H132.628V149.499Z" fill="white"/>
<path d="M128.055 155.521V153.956L-22.3829 153.956V155.521L128.055 155.521Z" fill="#C8D3FB"/>
<path d="M127.942 249.489V247.923L-22.4959 247.923V249.489L127.942 249.489Z" fill="#C8D3FB"/>
<path d="M128.08 55.3584V53.793L-22.514 53.793V55.3584L128.08 55.3584Z" fill="#C8D3FB"/>
<path d="M214.608 170.47L332.641 170.47V99.3998L214.608 99.3998V170.47Z" fill="#C8D3FB"/>
<path d="M220.448 164.526H326.741V105.196H220.448V164.526Z" fill="url(#paint3_linear_6390_7734)"/>
<path d="M229.948 156.383H317.299V113.177L229.948 113.177V156.383Z" fill="#D5DDFB"/>
<path d="M317.349 156.387L303.573 136.349C303.103 135.567 301.851 135.567 301.381 136.349L293.867 148.403L287.762 141.985C287.136 141.359 286.04 141.515 285.727 142.298L277.9 156.387H317.349Z" fill="#C8D3FB"/>
<path d="M290.58 123.357C290.58 125.705 292.458 127.74 294.963 127.74C297.311 127.74 299.346 125.862 299.346 123.357C299.346 121.009 297.468 118.974 294.963 118.974C292.615 119.13 290.58 121.009 290.58 123.357Z" fill="white"/>
<path d="M258.645 124.921C258.802 125.391 259.271 125.391 259.741 125.547C261.306 125.86 263.341 125.704 264.907 125.704C265.846 125.704 266.942 125.704 267.881 125.704C268.82 126.173 269.916 126.643 271.012 126.643C272.264 126.643 273.204 125.86 274.456 125.704C275.239 125.704 277.274 125.86 276.648 124.452C276.021 122.73 272.108 123.199 270.699 122.73C269.916 122.573 269.447 122.416 268.664 122.26C267.725 122.103 267.881 122.103 267.098 121.634C266.629 121.321 266.472 121.164 266.003 121.008C265.22 120.694 264.437 120.851 263.655 121.164C262.872 121.634 262.402 122.416 261.463 122.73C260.993 122.886 257.706 123.043 258.645 124.921Z" fill="white"/>
<path d="M247.218 128.679C248.626 129.148 250.348 129.305 251.914 129.148C252.697 128.992 254.105 128.992 254.732 128.365C255.201 127.896 255.201 127.113 254.732 126.8C254.262 126.33 253.792 126.33 253.166 126.487C252.227 126.017 251.288 125.861 250.192 126.017C249.722 126.017 249.409 126.33 248.939 126.33C248.626 126.33 248.157 126.017 247.844 126.017C247.531 126.017 247.061 125.861 246.748 126.017C244.869 126.487 245.965 128.209 247.218 128.679Z" fill="white"/>
<path d="M267.724 156.386L259.114 141.044C258.801 140.575 258.019 140.418 257.705 141.044L251.131 151.689L248.313 147.463C248 146.993 247.217 146.993 246.904 147.619L242.677 156.542L235.476 139.949C235.163 139.322 234.224 139.322 234.067 139.949L229.841 151.689V156.386H267.724Z" fill="#C8D3FB"/>
<path d="M182.253 85.1588C167.382 85.1588 155.328 73.105 155.328 58.2334H156.58C156.58 72.3223 168.008 83.9064 182.253 83.9064C196.342 83.9064 207.926 72.4788 207.926 58.2334H209.179C209.179 73.105 197.125 85.1588 182.253 85.1588Z" fill="#D5DDFB"/>
<path d="M181.939 37.2568L147.969 65.278H222.797L181.939 37.2568Z" fill="#C8D3FB"/>
<path opacity="0.22" d="M165.033 61.3643L129.185 176.893H233.442L199.473 61.3643H165.033Z" fill="url(#paint4_linear_6390_7734)"/>
<path d="M180.374 17.5322V33.8127V38.3524V38.509V40.7006V41.0137V45.8665H183.661V41.0137V40.7006V38.509V38.3524V33.8127V18.9411L180.374 17.5322Z" fill="#D5DDFB"/>
<path d="M187.418 52.9109H176.304V44.9272C176.304 42.7356 178.026 41.0137 180.218 41.0137H183.505C185.697 41.0137 187.418 42.7356 187.418 44.9272V52.9109Z" fill="#FFBF5B"/>
<path d="M188.201 66.2176C188.201 62.6171 185.383 59.7993 181.783 59.7993C178.183 59.7993 175.365 62.6171 175.365 66.2176C175.365 69.8181 178.183 72.6358 181.783 72.6358C185.383 72.7924 188.201 69.8181 188.201 66.2176Z" fill="#D5DDFB"/>
<path d="M181.939 70.2871C180.374 69.974 178.339 68.8782 177.869 67.1563C177.712 66.5301 176.773 66.8432 176.93 67.4693C177.399 69.3479 179.747 70.9133 181.626 71.2264C182.252 71.2264 182.409 70.4437 181.939 70.2871Z" fill="white"/>
<path d="M181.939 37.2568L144.525 65.278H219.353L181.939 37.2568Z" fill="#D5DDFB"/>
<path d="M183.348 40.7004H180.218C179.122 40.7004 178.339 39.7611 178.339 38.8219V35.691C178.339 34.5952 179.278 33.8125 180.218 33.8125H183.348C184.444 33.8125 185.227 34.7518 185.227 35.691V38.8219C185.384 39.7611 184.444 40.7004 183.348 40.7004Z" fill="#D5DDFB"/>
</g>
<path d="M178.558 48.0747L38.2959 48.356L38.7972 298.355L179.06 298.074L178.558 48.0747Z" fill="white"/>
<path d="M43.2422 38.8218L124.331 39.2914V49.7798L83.1606 49.9363L53.8871 50.0929C44.0249 50.0929 36.0412 58.0766 36.1977 67.9388L36.5108 271.601C36.5108 281.463 44.4945 289.447 54.3567 289.447L124.644 289.603V311.676L43.5552 312.459C33.693 312.459 25.7094 304.475 25.7094 294.613L25.2397 56.6677C25.3963 46.962 33.38 38.8218 43.2422 38.8218Z" fill="#1C0A76"/>
<path d="M32.5974 56.6677V294.613C32.5974 304.005 39.9549 311.833 49.191 312.459C49.6606 312.459 49.9737 312.459 50.4433 312.459H175.208C181.626 312.459 186.792 307.293 186.792 300.875V50.406C186.792 43.9877 181.626 38.8218 175.208 38.8218H50.4433C49.9737 38.8218 49.6606 38.8218 49.191 38.8218C39.9549 39.4479 32.5974 47.1186 32.5974 56.6677ZM43.3989 61.5205C43.3989 55.1022 48.5648 49.9363 54.983 49.9363H164.563C170.981 49.9363 176.147 55.1022 176.147 61.5205V277.706C176.147 284.124 170.981 289.29 164.563 289.29H54.983C48.5648 289.29 43.3989 284.124 43.3989 277.706V61.5205Z" fill="url(#paint5_linear_6390_7734)"/>
<path d="M95.0579 306.355H124.801C127.775 306.355 130.123 304.007 130.123 300.876C130.123 297.901 127.619 295.553 124.644 295.553H94.9013C91.927 295.553 89.5789 298.058 89.5789 301.032C89.7354 303.85 92.0835 306.355 95.0579 306.355Z" fill="#1C0A76"/>
<path d="M156.893 139.167H62.8103C57.6444 139.167 53.2612 134.94 53.2612 129.618V70.4446C53.2612 65.2787 57.4879 60.8955 62.8103 60.8955H156.893C162.058 60.8955 166.442 65.1222 166.442 70.4446V129.774C166.442 134.94 162.058 139.167 156.893 139.167Z" fill="#C8D3FB"/>
<path d="M116.191 84.9995H68.6021V86.7215H116.191V84.9995Z" fill="#1C0A76"/>
<path d="M148.752 84.9995H133.724V86.7215H148.752V84.9995Z" fill="#1C0A76"/>
<path d="M116.191 92.0439H68.6018V93.7659H116.191V92.0439Z" fill="#1C0A76"/>
<path d="M148.752 92.0444H133.724V93.7664H148.752V92.0444Z" fill="#1C0A76"/>
<path d="M116.191 99.0894H68.6018V100.811H116.191V99.0894Z" fill="#1C0A76"/>
<path d="M148.752 99.0894H133.724V100.811H148.752V99.0894Z" fill="#1C0A76"/>
<path d="M116.191 106.29H68.6018V108.012H116.191V106.29Z" fill="#1C0A76"/>
<path d="M148.752 106.29H133.724V108.012H148.752V106.29Z" fill="#1C0A76"/>
<path d="M116.191 113.334H68.6018V115.056H116.191V113.334Z" fill="#1C0A76"/>
<path d="M148.752 113.334H133.724V115.056H148.752V113.334Z" fill="#1C0A76"/>
<path d="M116.191 120.379H68.6018V122.101H116.191V120.379Z" fill="#1C0A76"/>
<path d="M148.752 120.379H133.724V122.101H148.752V120.379Z" fill="#1C0A76"/>
<path d="M151.57 278.959H68.2893C64.3758 278.959 61.0884 275.672 61.0884 271.758V260.017C61.0884 256.104 64.3758 252.816 68.2893 252.816H151.57C155.484 252.816 158.771 256.104 158.771 260.017V271.758C158.771 275.672 155.64 278.959 151.57 278.959Z" fill="url(#paint6_linear_6390_7734)"/>
<path d="M305.765 195.053C305.765 194.74 305.452 194.583 305.139 194.583C299.66 194.74 292.929 194.74 288.232 198.027C284.006 201.158 283.38 206.637 283.38 211.646C283.38 212.116 284.006 212.272 284.319 212.116C295.903 216.342 307.487 206.95 305.765 195.053Z" fill="#6A6AE8"/>
<path d="M279.466 217.281C279.466 213.524 278.683 209.61 275.709 207.106C272.421 204.131 267.569 202.409 263.655 200.374C263.185 200.218 262.559 200.531 262.872 201C264.594 205.54 264.438 211.019 267.569 214.933C270.23 218.22 274.77 219.472 278.84 218.22C278.996 218.22 279.153 218.064 279.153 217.907C279.309 217.75 279.466 217.437 279.466 217.281Z" fill="#6A6AE8"/>
<path d="M314.688 229.492C312.026 227.457 308.582 227.613 305.295 227.77C301.694 227.926 298.094 228.552 294.807 229.961C289.171 232.623 285.101 238.571 287.136 244.989C287.136 245.303 287.136 245.616 287.449 245.616C292.928 247.338 295.433 243.737 298.72 240.137C302.947 235.44 308.269 232.153 314.218 230.431C314.688 230.431 315.001 229.805 314.688 229.492Z" fill="#6A6AE8"/>
<path d="M327.524 243.111C327.524 243.111 327.368 243.111 327.368 242.954C325.019 242.015 322.984 240.137 320.949 238.258C318.601 236.223 316.253 234.344 313.592 233.875C312.339 233.718 310.931 233.718 309.522 234.188C303.73 236.066 300.129 242.172 299.503 247.964C299.503 248.12 299.503 248.277 299.659 248.277C299.659 248.277 299.659 248.277 299.659 248.433C299.503 248.746 299.816 249.216 300.129 249.216C305.138 249.842 309.991 249.216 314.844 248.277C319.227 247.338 324.08 246.555 327.837 244.207C328.15 243.737 327.994 243.267 327.524 243.111Z" fill="#6A6AE8"/>
<path d="M318.915 254.225C312.497 252.972 299.504 249.685 298.564 259.86C298.564 260.173 298.721 260.33 299.034 260.33C304.826 267.061 315.941 261.739 319.385 255.007C319.385 254.694 319.385 254.225 318.915 254.225Z" fill="#6A6AE8"/>
<path d="M278.683 233.875C276.961 230.118 273.047 226.361 269.29 224.952C268.977 224.795 268.508 225.108 268.508 225.578C268.508 232.936 266.786 244.52 274.769 248.59H274.926C275.083 248.903 275.709 249.059 275.865 248.59C278.37 244.05 281.031 238.884 278.683 233.875Z" fill="#6A6AE8"/>
<path d="M257.863 238.415C253.95 235.284 247.844 234.502 243.305 236.85C237.043 239.981 238.139 247.651 237.2 253.443C237.043 254.069 237.669 254.382 238.139 254.069C244.401 248.59 253.01 246.399 257.707 239.354C258.176 239.198 258.333 238.728 257.863 238.415Z" fill="#6A6AE8"/>
<path d="M258.02 244.207C257.863 243.894 257.55 243.894 257.237 244.05C257.081 243.894 256.768 243.737 256.455 243.894C253.324 245.616 249.723 247.964 249.097 251.721C248.314 256.261 250.819 260.644 251.132 265.027C251.132 265.653 252.071 265.81 252.228 265.184C253.011 260.957 257.394 258.922 259.116 255.165C260.525 252.034 259.898 247.181 258.02 244.207Z" fill="#6A6AE8"/>
<path d="M277.275 270.349C273.674 265.183 269.917 260.8 263.499 259.235C263.029 259.078 262.56 259.704 262.873 260.017C264.281 262.209 264.281 264.557 265.534 266.749C266.317 268.001 267.412 268.94 268.665 269.723C271.326 271.445 274.926 273.01 277.901 271.288C278.37 270.975 277.744 270.193 277.275 270.349Z" fill="#6A6AE8"/>
<path d="M285.415 264.244V264.088C282.91 260.018 282.754 255.008 279.31 251.564C278.997 251.251 278.527 251.408 278.37 251.721C276.649 254.382 275.866 257.669 277.118 260.8C278.527 264.088 281.658 265.027 284.945 265.34C285.728 265.34 285.885 264.714 285.415 264.244Z" fill="#6A6AE8"/>
<path d="M292.459 219.317C291.676 218.691 290.737 219.317 290.111 219.63C288.702 220.256 287.45 220.882 286.354 221.665C284.162 223.23 282.753 225.578 282.597 228.24V228.396V228.553C282.597 229.179 283.536 229.335 283.692 228.709C286.51 228.083 288.702 226.361 290.58 224.17C291.207 223.543 294.181 220.726 292.459 219.317Z" fill="#6A6AE8"/>
<path d="M293.711 264.714C293.555 264.558 293.555 264.558 293.398 264.401C294.181 259.548 294.494 253.756 289.641 250.938C289.328 250.782 288.859 250.938 288.859 251.251C287.606 256.417 289.015 261.74 292.929 265.497C293.555 266.123 294.338 265.34 293.711 264.714Z" fill="#6A6AE8"/>
<path d="M327.054 242.485C324.863 241.545 322.984 239.98 320.949 238.258C318.601 236.38 316.253 234.658 313.592 233.875C312.339 233.718 310.931 233.718 309.522 234.188C303.73 236.066 300.129 242.172 299.503 247.964C299.503 248.12 299.503 248.277 299.659 248.277C299.659 248.277 299.659 248.277 299.659 248.433C299.816 248.433 299.973 248.277 300.129 248.12C300.286 248.12 300.286 248.12 300.442 247.964C302.321 245.929 304.356 244.05 306.391 242.172C307.33 241.232 308.269 240.137 309.365 239.354C311.713 237.632 313.592 237.945 316.096 238.728C318.914 239.51 321.575 241.076 324.237 242.485C325.176 243.111 326.115 243.894 327.211 243.424C327.368 243.267 327.524 243.111 327.524 242.954C327.368 242.798 327.211 242.485 327.054 242.485Z" fill="#6A6AE8"/>
<path d="M276.179 261.896C275.552 259.705 275.083 257.357 274.3 255.165C275.396 251.564 275.709 247.964 275.552 244.52C275.709 244.52 275.865 244.364 276.022 244.207C276.648 242.015 276.961 239.98 276.805 237.789C276.805 237.006 275.552 237.006 275.709 237.789C275.709 239.354 275.709 240.763 275.396 242.328C275.239 240.607 274.77 238.885 274.3 237.319C274.144 236.536 273.048 236.849 273.204 237.632C274.77 242.955 274.926 248.277 273.674 253.6C272.578 250.782 271.169 248.277 269.447 245.929C265.221 240.45 257.393 237.163 251.288 239.667C251.288 239.511 251.132 239.198 250.819 239.198C248.471 238.571 246.122 239.041 243.931 240.293C243.305 240.606 243.931 241.702 244.557 241.233C246.279 240.137 248.157 239.824 250.036 240.293C248.627 241.076 247.375 242.172 246.122 243.737C245.653 244.364 246.749 244.99 247.062 244.364C250.036 240.293 255.358 239.041 260.055 240.45C261.464 240.92 262.716 241.546 263.812 242.328C258.959 242.172 255.202 245.459 251.758 248.747C251.288 249.216 252.071 249.999 252.541 249.529C253.167 248.903 253.949 248.277 254.576 247.651C254.419 248.747 254.419 249.999 254.419 251.095C254.419 251.878 255.671 251.878 255.515 251.095C255.358 249.529 255.515 248.121 255.828 246.712C255.828 246.555 255.828 246.555 255.828 246.555C258.176 244.677 260.837 243.268 264.125 243.581C264.438 243.581 264.594 243.424 264.594 243.268C267.256 245.303 269.291 248.121 270.7 251.095C273.674 257.043 275.396 263.775 276.335 270.506C273.987 269.88 271.952 268.628 270.23 266.749C269.76 266.123 268.978 267.062 269.447 267.532C270.23 268.471 271.169 269.254 272.265 269.88C271.639 269.88 271.013 269.88 270.23 269.723C269.447 269.567 269.134 270.663 269.917 270.819C271.013 270.976 272.108 271.132 273.204 270.976C273.517 270.976 273.674 270.819 273.674 270.663C274.457 270.976 275.396 271.289 276.335 271.602C276.335 271.602 276.335 271.602 276.492 271.602C276.961 274.889 277.118 278.177 277.274 281.308C277.274 282.09 278.527 282.09 278.37 281.308C278.527 274.42 277.744 268.002 276.179 261.896Z" fill="#312890"/>
<path d="M295.277 238.102C294.181 238.885 293.242 239.667 292.302 240.45C292.929 238.415 293.711 236.537 294.964 234.815C295.433 234.188 294.338 233.562 294.024 234.188C292.459 236.38 291.52 238.728 290.894 241.233C290.894 241.389 290.894 241.546 291.05 241.702C288.545 244.207 286.354 247.025 284.475 250.156C284.162 246.242 283.849 242.172 283.693 238.258C283.536 235.441 283.38 232.31 283.223 229.022C284.632 227.3 286.041 225.422 288.076 224.483C288.702 224.17 288.232 223.23 287.45 223.543C285.728 224.326 284.319 225.735 283.223 227.144C283.223 225.579 283.223 224.013 283.38 222.604C283.536 222.448 283.536 222.291 283.38 222.135C284.006 213.994 286.354 206.324 294.181 202.723C294.807 202.41 294.337 201.471 293.555 201.784C291.52 202.723 289.954 203.819 288.545 205.228C288.545 204.132 288.702 203.036 289.015 201.941C289.328 201.314 288.232 201.001 287.919 201.627C287.293 203.193 287.137 204.602 287.45 206.324C284.162 210.237 282.753 215.56 282.284 221.039C280.562 219.16 278.996 217.125 277.274 215.247C277.431 215.09 277.587 214.934 277.587 214.777C277.431 213.212 276.961 211.646 276.022 210.394C275.552 209.768 274.613 210.394 275.083 211.02C275.709 211.959 276.179 213.055 276.335 214.307C275.709 213.525 275.083 212.899 274.457 212.116C273.987 211.49 273.204 212.429 273.674 212.899C276.492 216.186 279.309 219.473 282.127 222.761C281.971 224.796 281.971 226.831 281.971 228.709C281.971 228.709 281.971 228.709 281.971 228.866C281.814 229.179 281.814 229.336 282.127 229.492C282.127 231.371 282.284 233.249 282.284 235.128C282.597 244.364 283.38 253.443 284.319 262.523C282.284 261.427 281.031 259.235 280.092 257.2C279.779 256.574 278.84 257.044 279.153 257.826C280.405 260.174 281.658 262.679 284.162 263.775C284.319 263.775 284.319 263.775 284.475 263.775C285.101 269.567 285.884 275.516 286.823 281.308C286.98 282.09 288.076 281.777 287.919 280.995C286.354 271.446 285.258 261.74 284.475 252.191C284.632 252.191 284.632 252.034 284.788 251.878C287.45 246.868 291.05 242.485 295.746 239.041C296.373 238.728 295.903 237.789 295.277 238.102Z" fill="#312890"/>
<path d="M314.218 239.041C311.87 239.041 309.522 239.51 307.643 240.606C308.426 239.667 309.365 238.884 310.461 238.101C311.087 237.632 310.461 236.693 309.835 237.162C307.956 238.571 306.234 240.293 304.825 242.328L304.669 242.485C300.755 245.615 297.937 250.155 296.059 254.695C294.963 257.356 294.18 260.174 293.554 262.992C292.928 261.896 292.615 260.644 292.145 259.548C291.832 258.609 291.519 257.669 290.58 257.2C289.954 256.73 289.328 257.826 289.954 258.139C290.893 258.765 291.049 260.331 291.363 261.426C291.676 262.366 291.989 263.305 292.615 264.088C292.771 264.244 292.928 264.401 293.085 264.401C291.676 271.289 291.363 278.646 290.58 285.534C290.58 286.317 291.676 286.317 291.676 285.534C292.302 279.116 292.771 272.384 293.867 265.966C294.024 265.966 294.024 265.966 294.18 265.81C296.372 263.461 298.564 260.957 301.381 259.391C302.164 260.174 303.103 260.8 304.199 261.113C304.825 261.426 305.138 260.174 304.512 260.017C303.729 259.704 302.947 259.391 302.477 258.765C303.26 258.452 304.043 257.982 304.825 257.826C305.608 257.669 305.295 256.573 304.512 256.73C303.416 257.043 302.321 257.513 301.381 258.139C301.225 258.139 301.068 258.295 300.912 258.452C298.407 259.861 296.372 262.052 294.337 264.088C294.65 262.209 295.12 260.487 295.746 258.765C296.842 255.165 298.564 251.251 301.068 247.807C302.321 247.337 303.729 247.024 305.138 246.868C305.921 246.711 305.608 245.615 304.825 245.772C304.043 245.929 303.103 246.085 302.321 246.242C305.295 242.798 309.208 240.293 314.061 240.45C315.001 240.293 315.001 239.041 314.218 239.041Z" fill="#312890"/>
<path d="M304.669 274.888L303.73 280.68L302.165 290.856L298.564 313.085H272.422L268.821 290.856L267.099 280.68L266.16 274.888H304.669Z" fill="#C8D3FB"/>
<path opacity="0.3" d="M277.118 280.68L276.179 274.888H266.16L267.099 280.68L268.821 290.856L272.422 313.085H282.44L278.84 290.856L277.118 280.68Z" fill="#1C0A76"/>
<path opacity="0.64" d="M295.433 311.363C294.65 311.363 294.181 310.893 294.181 310.58L298.72 276.767C298.72 276.297 299.347 275.984 299.973 275.984C300.599 275.984 301.225 276.454 301.069 276.767L296.529 310.58C296.685 311.05 296.059 311.363 295.433 311.363Z" fill="white"/>
<path d="M169.103 160.611V234.186C169.103 238.256 165.815 241.7 161.589 241.7H55.7658C51.6957 241.7 48.2517 238.413 48.2517 234.186V160.611C48.2517 156.071 52.0087 152.314 56.5485 152.314H160.962C165.502 152.314 169.103 155.915 169.103 160.611Z" fill="#C8D3FB"/>
<mask id="mask2_6390_7734" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="48" y="152" width="122" height="90">
<path d="M169.103 160.61V234.185C169.103 238.256 165.815 241.699 161.589 241.699H55.7658C51.6957 241.699 48.2517 238.412 48.2517 234.185V160.61C48.2517 156.07 52.0087 152.313 56.5485 152.313H160.962C165.502 152.313 169.103 155.914 169.103 160.61Z" fill="white"/>
</mask>
<g mask="url(#mask2_6390_7734)">
<path d="M181.939 237.631L176.303 237.318C175.521 237.318 174.894 236.691 174.894 235.909V232.152C174.894 231.369 175.521 230.743 176.303 230.743L182.095 230.586V227.925L176.616 228.082C175.834 228.082 175.208 227.455 175.051 226.673L174.894 222.916C174.894 222.133 174.268 221.663 173.486 221.507L153.292 220.254C152.509 220.254 152.039 219.628 151.883 219.002L150.943 202.408C150.943 201.626 151.57 200.843 152.509 201L163.467 201.469C164.25 201.469 164.876 200.843 165.032 200.06L165.345 189.572C165.345 188.789 165.972 188.163 166.754 188.163H177.399C178.338 188.163 178.965 188.946 178.808 189.729L177.869 197.712C177.712 198.495 178.338 199.121 179.121 199.278L181.939 199.591V196.46C181.469 196.147 181.313 195.677 181.313 195.208L181.626 189.415C181.626 189.102 181.782 188.946 181.939 188.789V185.032H162.215C161.432 185.032 160.806 185.658 160.806 186.441V197.086C160.806 197.869 160.023 198.495 159.24 198.495L149.065 197.869C148.126 197.869 147.5 198.495 147.5 199.278L148.595 221.82C148.595 222.603 149.221 223.072 150.004 223.072L170.042 224.481C170.824 224.481 171.294 225.107 171.451 225.89L172.077 239.04C172.077 239.822 172.703 240.448 173.486 240.448H180.53L181.939 237.631Z" fill="url(#paint7_linear_6390_7734)"/>
<path d="M159.084 148.871L162.684 164.526C162.841 165.152 163.467 165.621 164.093 165.621H179.278C180.06 165.621 180.687 166.248 180.687 167.03L180.53 171.57C180.53 172.353 181 172.979 181.782 172.979H181.939V155.29C181.939 154.507 181.782 153.881 181.626 153.255V159.986C181.626 160.769 181 161.395 180.217 161.395H169.259C168.476 161.395 168.007 160.925 167.85 160.299L165.502 148.715H159.084V148.871Z" fill="url(#paint8_linear_6390_7734)"/>
<path d="M46.8431 217.907C51.6959 216.968 59.523 215.246 59.523 215.246C60.3057 215.089 61.245 215.559 61.245 216.498L62.967 230.117C62.967 230.743 63.4366 231.213 64.0628 231.369L83.9437 235.44C84.5699 235.596 85.0395 236.066 85.0395 236.692L85.5091 242.327C85.5091 242.484 85.5091 242.484 85.5091 242.641H88.0138L86.918 225.577C86.918 224.795 87.3876 224.325 88.1703 224.168L97.2498 222.603C97.2498 222.603 97.2498 222.603 97.4064 222.603L108.991 219.785C109.773 219.629 110.243 219.003 110.086 218.22L108.521 207.888C108.364 207.105 108.991 206.323 109.773 206.323L138.107 201.626C138.734 201.47 139.203 200.844 139.047 200.217L137.481 182.841C137.481 182.058 137.951 181.432 138.89 181.276L147.343 180.806C148.126 180.806 148.752 180.023 148.752 179.241L144.839 154.037C144.682 153.411 144.056 152.785 143.43 152.785H114.47C113.687 152.785 113.061 152.315 113.061 151.533L112.748 148.715H108.051L109.147 157.012C109.304 157.638 109.93 158.264 110.556 158.264H121.827H137.951C138.577 158.264 139.203 158.734 139.36 159.36L142.491 174.701C142.647 175.484 142.178 176.11 141.395 176.266L133.411 177.832C132.628 177.988 132.159 178.615 132.315 179.241L133.568 196.304C133.568 196.93 133.255 197.556 132.628 197.713L105.703 202.722C104.92 202.879 104.451 203.505 104.451 204.288L105.703 215.089C105.86 215.872 105.234 216.498 104.451 216.654L96.7802 217.75C96.7802 217.75 96.7802 217.75 96.6237 217.75L84.7264 220.725C83.9437 220.881 83.4741 221.507 83.6306 222.133L84.2568 229.178C84.4133 230.117 83.4741 230.9 82.5348 230.743L67.8198 228.395C67.1936 228.239 66.724 227.769 66.5675 227.143L64.6889 213.993L70.3245 212.741C70.9507 212.584 71.4203 211.958 71.4203 211.332L69.5418 183.937C69.5418 183.311 69.0721 182.841 68.446 182.685L60.4623 180.963C59.8361 180.806 59.523 180.337 59.3665 179.867L54.044 152.315C53.8875 151.533 53.2613 151.063 52.4786 151.22L47.9389 151.533C47.3127 152.472 46.8431 153.568 46.6865 154.82L49.5043 154.663C50.287 154.663 50.9132 155.133 51.0697 155.759L55.766 182.372C55.9225 182.841 56.2356 183.311 56.8618 183.467L65.6282 185.502C66.2544 185.659 66.724 186.129 66.724 186.755L68.446 209.297C68.446 209.923 67.9763 210.549 67.3502 210.706L46.8431 214.463V217.907Z" fill="url(#paint9_linear_6390_7734)"/>
<path d="M133.724 162.491C134.35 162.491 134.976 162.96 135.133 163.586L136.541 170.474C136.698 171.257 136.228 171.883 135.446 172.04L130.28 173.292C129.497 173.449 128.714 172.979 128.558 172.196L126.679 164.056C126.523 163.117 127.149 162.334 128.088 162.334H133.724V162.491Z" fill="url(#paint10_linear_6390_7734)"/>
<path d="M115.252 240.135L115.565 242.64H124.488L134.35 240.918H134.507L140.925 240.449C141.708 240.449 142.334 240.918 142.491 241.701L142.647 242.64H145.778L145.621 241.544C145.465 240.762 146.091 239.979 146.874 239.979L152.353 239.509C153.135 239.509 153.762 239.979 153.918 240.605L154.231 242.484H159.554L158.458 235.283C158.301 234.5 157.675 234.03 156.892 234.03L133.568 235.439H133.411L116.348 238.257C115.722 238.727 115.096 239.353 115.252 240.135Z" fill="url(#paint11_linear_6390_7734)"/>
<path d="M169.729 213.053C169.729 213.836 169.102 214.462 168.32 214.462H156.892C156.109 214.462 155.483 213.836 155.483 213.053V212.114C155.483 211.331 156.109 210.705 157.049 210.705L168.476 211.018C169.259 211.018 169.885 211.644 169.885 212.427V213.053H169.729Z" fill="url(#paint12_linear_6390_7734)"/>
<path d="M72.6726 148.87L72.8291 154.818C72.8291 155.444 73.2988 156.071 74.0815 156.071L87.7007 158.575H87.8572L95.5278 160.923C96.154 161.08 96.4671 161.706 96.4671 162.176V170.942C96.4671 171.412 96.154 171.881 95.8409 172.195L90.9881 175.169C90.5185 175.482 90.2054 176.108 90.3619 176.578L90.675 177.83C90.8316 178.769 92.0839 179.239 92.8666 178.769L99.911 174.23C100.381 173.916 100.537 173.603 100.537 173.134V159.515C100.537 158.888 100.068 158.419 99.4414 158.106L87.2311 154.662H87.0745L78.4647 153.253C77.8385 153.096 77.3689 152.627 77.2123 152L77.0558 149.026H72.6726V148.87Z" fill="url(#paint13_linear_6390_7734)"/>
<path d="M120.418 180.022C121.2 179.866 121.826 180.492 121.983 181.118L124.018 193.642C124.175 194.424 123.548 195.207 122.609 195.207H118.069C117.443 195.207 116.817 194.737 116.66 194.111L113.999 182.214C113.843 181.431 114.469 180.649 115.252 180.492L120.418 180.022Z" fill="url(#paint14_linear_6390_7734)"/>
<path d="M107.738 181.587C108.364 181.587 108.99 182.057 109.147 182.683L111.651 193.641C111.808 194.58 111.182 195.363 110.242 195.363H105.859C105.233 195.363 104.607 194.894 104.45 194.267L101.789 183.309C101.633 182.37 102.259 181.587 103.198 181.587H107.738Z" fill="url(#paint15_linear_6390_7734)"/>
<path d="M104.138 229.177L109.617 228.551C110.4 228.394 111.026 228.864 111.182 229.646L112.435 234.969C112.591 235.751 111.965 236.534 111.182 236.691L105.077 237.317C104.294 237.317 103.512 236.847 103.512 236.065L102.885 230.742C102.729 229.959 103.355 229.177 104.138 229.177Z" fill="url(#paint16_linear_6390_7734)"/>
<path d="M168.32 208.357H156.892C156.109 208.357 155.483 207.731 155.483 206.948V206.009C155.483 205.226 156.109 204.6 157.049 204.6L168.476 204.913C169.259 204.913 169.885 205.539 169.885 206.322V206.948C169.729 207.731 169.102 208.357 168.32 208.357Z" fill="url(#paint17_linear_6390_7734)"/>
<path d="M118.539 223.386C117.757 223.386 116.974 222.916 116.974 222.133L116.348 216.811C116.191 216.028 116.817 215.402 117.6 215.246L123.079 214.619C123.862 214.463 124.488 214.932 124.644 215.715L125.897 221.038C126.053 221.82 125.427 222.603 124.644 222.76L118.539 223.386Z" fill="url(#paint18_linear_6390_7734)"/>
</g>
<path d="M126.993 199.591C126.993 195.991 124.018 193.017 120.418 193.017C116.817 193.017 113.843 195.991 113.843 199.591C113.843 202.879 116.191 205.54 119.322 206.166V221.194H121.67V206.166C124.644 205.697 126.993 202.879 126.993 199.591Z" fill="url(#paint19_linear_6390_7734)"/>
<path d="M221.231 293.832L211.682 294.301C212.308 302.128 208.395 305.885 200.254 306.668C195.558 307.138 195.871 312.93 195.871 312.93H222.014C222.014 312.93 225.145 310.269 221.857 304.32C221.075 302.754 221.231 293.832 221.231 293.832Z" fill="#FFD2A7"/>
<path d="M200.254 306.667C195.558 307.136 195.871 312.928 195.871 312.928H222.014C222.014 312.928 225.145 310.267 221.857 304.319C220.135 305.258 215.596 306.354 209.96 302.91C207.769 304.475 203.542 306.354 200.254 306.667Z" fill="#1C0A76"/>
<path d="M205.733 305.257C205.733 305.257 210.273 302.596 210.743 300.248C211.212 297.899 214.03 300.091 214.343 300.717C214.5 301.343 211.056 305.1 205.733 305.257Z" fill="#1C0A76"/>
<path d="M212.465 165.466C208.864 180.807 209.96 209.768 209.334 234.814C208.864 254.852 209.177 284.752 208.708 297.275C208.708 297.275 219.509 299.467 224.049 297.275C224.049 297.275 231.876 245.459 233.911 238.258C235.789 231.214 242.208 185.66 237.042 166.249C232.189 146.837 214.03 159.361 212.465 165.466Z" fill="#3B31A1"/>
<path d="M236.729 185.816C236.729 185.816 230.624 214.933 228.746 234.971C227.963 242.955 224.049 297.275 224.049 297.275C224.049 297.275 229.372 261.583 231.25 251.877C233.912 238.258 241.269 202.723 241.269 202.723L236.729 185.816Z" fill="#1C0A76"/>
<path d="M253.48 293.832L263.029 294.301C262.402 302.128 266.316 305.885 274.456 306.668C279.153 307.138 278.839 312.93 278.839 312.93H252.697C252.697 312.93 249.566 310.269 252.853 304.32C253.636 302.754 253.48 293.832 253.48 293.832Z" fill="#FFD2A7"/>
<path d="M274.456 306.667C279.152 307.136 278.839 312.928 278.839 312.928H252.697C252.697 312.928 249.566 310.267 252.853 304.319C254.575 305.258 259.115 306.354 264.75 302.91C266.785 304.475 271.169 306.354 274.456 306.667Z" fill="#1C0A76"/>
<path d="M268.977 305.257C268.977 305.257 264.438 302.596 263.968 300.248C263.498 297.899 260.681 300.091 260.368 300.717C260.054 301.343 263.655 305.1 268.977 305.257Z" fill="#1C0A76"/>
<path d="M266.003 297.275C266.003 297.275 255.201 299.467 250.661 297.275C250.661 297.275 244.4 243.737 242.365 236.693C240.486 229.648 232.502 185.66 237.512 166.249C242.678 146.837 260.68 159.361 262.245 165.466C262.872 167.971 263.341 171.101 263.654 174.858C265.533 193.644 266.316 224.796 265.846 241.546C265.689 246.085 265.689 250.938 265.689 255.635C265.533 271.602 265.689 287.726 266.003 297.275Z" fill="#3B31A1"/>
<path d="M263.655 174.858C263.341 174.232 263.028 173.606 262.715 173.137C261.933 171.571 261.15 170.319 259.428 169.849C258.332 169.536 257.08 169.849 255.984 169.849C254.575 169.849 249.722 169.379 249.566 171.571C253.01 178.772 256.297 186.13 258.645 193.957C260.993 201.94 263.028 209.768 262.715 218.064C262.559 222.604 262.246 227.144 262.559 231.684C262.872 236.536 263.968 241.233 264.75 245.929C265.376 249.216 265.533 252.504 265.533 255.791C265.533 251.095 265.69 246.242 265.69 241.702C266.316 224.796 265.533 193.487 263.655 174.858Z" fill="#1C0A76"/>
<path d="M224.206 126.957C221.075 133.062 200.725 151.534 196.968 155.135C192.428 159.361 182.722 154.665 184.757 149.342C186.636 144.646 208.708 119.912 211.839 117.721C217.631 113.651 228.12 119.286 224.206 126.957Z" fill="#FFD2A7"/>
<path d="M214.187 141.358C220.918 134.94 226.24 125.704 227.962 122.417C232.033 114.433 222.797 107.702 217.004 111.615C215.596 112.554 205.264 118.973 199.472 126.174C201.82 133.531 212.778 140.889 214.187 141.358Z" fill="#C8D3FB"/>
<path d="M226.084 109.267C226.084 109.267 220.448 108.797 217.317 111.771C214.343 114.746 209.177 128.208 211.056 143.549C212.934 158.891 207.925 185.816 207.925 185.816C207.925 185.816 234.381 191.921 267.411 184.877C267.411 184.877 264.906 128.365 257.079 113.18C254.575 108.327 242.99 108.327 241.268 108.171C239.39 108.014 226.084 109.267 226.084 109.267Z" fill="#6A6AE8"/>
<path d="M227.493 102.534C227.493 102.534 228.432 107.857 226.71 108.483C224.988 109.109 222.797 109.422 222.797 109.422C222.797 109.422 231.876 122.728 242.364 108.17C242.364 108.17 239.234 108.17 238.294 106.918C237.355 105.665 236.729 99.4036 237.199 95.3335L227.493 102.534Z" fill="#FFD2A7"/>
<path d="M238.295 107.074C237.355 105.822 236.729 99.5603 237.199 95.4902L231.72 99.5603C232.816 100.5 234.538 103.317 234.381 103.474C235.79 106.135 236.573 110.049 233.755 112.084C231.563 113.649 228.745 113.649 226.084 112.866C229.685 115.528 235.79 117.563 242.365 108.327C242.365 108.17 239.234 108.327 238.295 107.074Z" fill="#FFBC8E"/>
<path d="M185.853 154.664C181.47 149.812 171.451 127.739 169.416 123.669C167.068 118.66 173.173 112.554 176.147 117.407C178.965 122.103 197.124 147.62 198.063 150.751C199.942 156.23 191.489 160.77 185.853 154.664Z" fill="#FFD2A7"/>
<path d="M242.991 87.6646C242.835 87.195 239.86 84.6903 239.547 84.8469C239.547 84.8469 239.704 95.4918 239.234 96.431C238.921 97.2138 238.295 98.7792 239.391 99.0923C240.33 99.4054 241.582 98.9357 242.052 98.153C245.339 93.1436 243.148 88.7604 242.991 87.6646Z" fill="#1C0A76"/>
<path d="M222.797 81.0894V97.2133C222.797 101.596 226.71 105.04 231.406 105.04C236.103 105.04 240.016 101.44 240.016 97.2133V96.9002C240.016 96.9002 244.4 97.8394 244.4 92.9866C244.4 88.1338 241.582 88.76 241.582 88.76V81.0894H222.797Z" fill="#FFD2A7"/>
<path d="M241.582 88.9164V79.0542H235.007V82.6547V99.4048C235.007 102.379 232.189 104.727 229.215 104.571C228.276 104.571 227.493 104.258 226.71 103.945C228.119 104.727 229.685 105.197 231.407 105.197C236.103 105.197 240.017 101.596 240.017 97.3697V97.0566C240.017 97.0566 244.4 97.9959 244.4 93.1431C244.4 88.1337 241.582 88.9164 241.582 88.9164Z" fill="#FFBC8E"/>
<path d="M241.895 73.1055C237.355 65.2784 221.074 75.6102 217.787 70.9139C215.752 73.1055 218.257 81.0892 221.388 81.8719C223.423 82.3416 233.441 82.0285 235.476 81.0892C236.416 84.5332 237.198 91.4211 239.077 91.4211C240.016 91.4211 241.895 89.8556 241.582 88.7598C246.434 88.1337 246.434 74.5144 241.895 73.1055Z" fill="#1C0A76"/>
<path d="M292.928 161.709L282.753 192.078C282.127 194.113 279.935 195.209 277.9 194.583L227.493 177.676C225.615 177.05 224.676 175.015 225.302 173.136L235.634 142.454C236.26 140.419 238.451 139.323 240.486 139.949L290.58 156.856C292.615 157.482 293.711 159.674 292.928 161.709Z" fill="#C8D3FB"/>
<path d="M290.424 160.77L280.248 191.14C279.622 193.175 277.431 194.27 275.396 193.644L224.989 176.738C223.11 176.111 222.171 174.076 222.797 172.198L233.129 141.515C233.755 139.48 235.947 138.385 237.982 139.011L288.075 155.917C290.111 156.7 291.206 158.735 290.424 160.77Z" fill="url(#paint20_linear_6390_7734)"/>
<path opacity="0.34" d="M249.253 184.877L244.087 183.155L246.748 142.141L252.071 143.863L249.253 184.877Z" fill="#DAE7FF"/>
<path opacity="0.34" d="M266.472 190.67L255.201 186.912L257.862 145.742L269.133 149.655L266.472 190.67Z" fill="#DAE7FF"/>
<path d="M265.69 118.033C270.699 122.73 282.596 147.62 284.944 152.16C287.762 157.795 282.44 164.057 277.43 161.396C273.047 159.204 254.575 130.87 253.323 127.113C251.131 120.694 259.428 112.241 265.69 118.033Z" fill="#FFD2A7"/>
<path d="M275.395 128.678C270.072 121.007 261.775 114.276 258.645 112.084C251.444 106.918 243.303 115.058 246.434 121.32C247.217 122.886 251.444 131.652 257.549 138.383C265.219 137.288 274.768 129.93 275.395 128.678Z" fill="#C8D3FB"/>
<path d="M233.598 186.757C234.381 184.409 235.163 182.061 234.381 183.783C233.441 185.974 230.467 185.818 231.406 183.626C232.659 180.965 233.755 177.677 235.79 175.329C237.981 172.825 245.652 172.355 248.313 170.633C249.409 170.007 252.227 175.173 251.6 176.112C249.722 179.086 245.652 179.869 245.339 180.339C244.869 181.748 244.713 182.687 244.399 184.096C243.93 185.974 240.956 186.757 241.269 184.878C241.582 183.783 240.956 183.783 240.486 185.348C239.86 187.383 236.729 188.166 237.198 185.974C237.355 185.035 237.199 184.722 236.885 185.818C236.416 188.479 232.815 189.105 233.598 186.757Z" fill="#FFD2A7"/>
<path d="M283.065 161.238C278.369 165.778 256.453 176.267 252.383 178.302C247.53 180.806 241.112 174.858 245.965 171.727C250.504 168.753 275.708 150.124 278.682 149.028C284.161 147.306 289.014 155.603 283.065 161.238Z" fill="#FFD2A7"/>
<path d="M175.051 112.241C174.738 111.928 172.86 110.989 171.294 110.676C170.668 109.58 170.355 108.328 170.355 106.919C170.355 105.197 170.355 103.788 169.259 102.379C169.103 102.222 168.79 102.066 168.477 102.222C167.85 102.535 167.85 103.318 167.694 103.944C167.694 104.414 167.537 104.727 167.537 105.197C167.537 104.101 167.224 103.162 166.442 102.222C166.285 102.066 165.972 101.909 165.659 102.066C165.033 102.379 165.033 103.162 164.876 103.788C164.876 103.944 164.876 103.944 164.876 104.101C164.876 104.101 164.876 103.944 164.72 103.944C164.563 103.788 164.25 103.631 163.937 103.788C163.311 104.101 163.311 104.884 163.154 105.51C162.998 106.292 162.841 107.232 162.841 108.171C162.684 107.858 162.371 107.701 162.058 107.388C161.902 107.232 161.589 107.232 161.276 107.388C160.649 107.858 160.806 108.484 160.963 109.11C161.119 110.832 161.276 112.711 161.745 114.433C162.684 117.25 165.815 120.225 168.477 120.851C169.103 121.164 169.729 121.477 170.042 121.79C170.668 122.416 175.364 123.669 176.147 120.068C176.617 117.094 177.243 114.276 175.051 112.241Z" fill="#FFD2A7"/>
<path d="M162.214 114.276L172.546 112.397L169.572 92.2031L159.24 93.9251L162.214 114.276Z" fill="url(#paint21_linear_6390_7734)"/>
<path d="M159.241 93.1424L165.189 92.2031L165.346 93.1424L162.371 93.612L160.18 93.9251C159.397 94.0816 158.927 94.8643 159.084 95.6471L161.432 111.928C161.589 112.71 162.215 113.336 162.998 113.18L168.163 112.397L168.477 114.276L162.528 115.371C161.745 115.528 161.119 114.902 160.962 114.119L158.145 94.8643C157.988 94.0816 158.614 93.2989 159.241 93.1424Z" fill="#1C0A76"/>
<path d="M158.927 94.7074L161.745 113.962C161.901 114.745 162.528 115.371 163.154 115.371C163.154 115.371 163.154 115.371 163.31 115.371L172.077 113.962C172.859 113.806 173.329 113.023 173.172 112.24L170.355 92.9855C170.198 92.2028 169.572 91.5766 168.789 91.7331L160.023 93.142C160.023 93.142 160.023 93.142 159.866 93.142C159.24 93.142 158.771 93.9247 158.927 94.7074ZM170.824 111.927L163.623 113.18C162.841 113.336 162.214 112.71 162.058 111.927L159.866 95.6467C159.71 94.864 160.179 94.0813 160.962 93.9247L163.154 93.6116L163.31 93.9247C163.31 94.0813 163.623 94.2378 163.78 94.2378L165.658 93.9247C165.815 93.9247 165.971 93.7682 165.971 93.4551V93.142L168.163 92.8289C168.946 92.6724 169.572 93.2986 169.729 94.0813L172.077 110.362C172.077 110.988 171.607 111.771 170.824 111.927Z" fill="url(#paint22_linear_6390_7734)"/>
<path d="M171.45 105.98C171.607 105.666 172.077 105.51 172.39 105.823C173.799 107.075 175.677 108.484 176.46 110.206C177.086 111.928 176.929 114.12 176.773 115.842C176.773 116.311 176.303 116.468 175.99 116.311C175.834 116.468 175.52 116.468 175.364 116.311C173.329 115.059 174.112 113.181 173.485 111.302C172.703 109.423 170.355 108.328 171.45 105.98Z" fill="#FFD2A7"/>
<path d="M269.29 0C251.287 0 236.729 14.5585 236.729 32.5609C236.729 43.832 242.364 53.6942 251.131 59.6428C252.54 63.8695 253.792 69.6616 251.913 72.4793C251.913 72.4793 260.21 73.7317 267.255 65.1218C267.881 65.1218 268.663 65.2784 269.29 65.2784C287.292 65.2784 301.851 50.7199 301.851 32.7175C301.851 14.715 287.292 0 269.29 0Z" fill="#6A6AE8"/>
<path d="M281.017 14.3335V16.8335C282.117 16.8335 283.167 17.2835 283.933 18.0335C284.733 18.8502 285.167 19.9002 285.167 21.0002V25.0335C285.167 26.2668 284.617 26.8335 283.367 26.8335H280.167V17.6835C280.167 17.2168 280.55 16.8335 281.017 16.8335V14.3335ZM281.017 14.3335C279.167 14.3335 277.667 15.8335 277.667 17.6835V29.3335H283.367C286 29.3335 287.667 27.6668 287.667 25.0335V21.0002C287.667 19.1668 286.917 17.5002 285.717 16.2835C284.5 15.0835 282.85 14.3502 281.017 14.3335C281.033 14.3335 281.017 14.3335 281.017 14.3335Z" fill="#FCFCFC"/>
<path d="M262.666 14.3335H261C256 14.3335 254.333 17.3168 254.333 21.0002V22.6668V46.0002C254.333 47.3835 255.9 48.1668 257 47.3335L259.85 45.2002C260.516 44.7002 261.45 44.7668 262.05 45.3668L264.816 48.1502C265.466 48.8002 266.533 48.8002 267.183 48.1502L269.983 45.3502C270.566 44.7668 271.5 44.7002 272.15 45.2002L275 47.3335C276.1 48.1502 277.666 47.3668 277.666 46.0002V17.6668C277.666 15.8335 279.166 14.3335 281 14.3335H262.666ZM270.583 28.9168H267.25V32.2502C267.25 32.9335 266.683 33.5002 266 33.5002C265.316 33.5002 264.75 32.9335 264.75 32.2502V28.9168H261.416C260.733 28.9168 260.166 28.3502 260.166 27.6668C260.166 26.9835 260.733 26.4168 261.416 26.4168H264.75V23.0835C264.75 22.4002 265.316 21.8335 266 21.8335C266.683 21.8335 267.25 22.4002 267.25 23.0835V26.4168H270.583C271.266 26.4168 271.833 26.9835 271.833 27.6668C271.833 28.3502 271.266 28.9168 270.583 28.9168Z" fill="#FCFCFC"/>
<defs>
<linearGradient id="paint0_linear_6390_7734" x1="-51.5778" y1="223.809" x2="406.467" y2="102.854" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint1_linear_6390_7734" x1="-30.7962" y1="302.508" x2="427.248" y2="181.553" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint2_linear_6390_7734" x1="-24.7485" y1="153.137" x2="130.225" y2="153.137" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint3_linear_6390_7734" x1="220.515" y1="134.859" x2="326.78" y2="134.859" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint4_linear_6390_7734" x1="181.276" y1="176.865" x2="181.276" y2="61.3722" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint5_linear_6390_7734" x1="125.995" y1="188.018" x2="-79.0758" y2="9.55969" gradientUnits="userSpaceOnUse">
<stop stop-color="#6A6AE8"/>
<stop offset="1" stop-color="#312890"/>
</linearGradient>
<linearGradient id="paint6_linear_6390_7734" x1="61.1023" y1="265.865" x2="158.838" y2="265.865" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFAE00"/>
<stop offset="1" stop-color="#FF7800"/>
</linearGradient>
<linearGradient id="paint7_linear_6390_7734" x1="147.652" y1="212.613" x2="182.108" y2="212.613" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint8_linear_6390_7734" x1="159.15" y1="160.903" x2="182.109" y2="160.903" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint9_linear_6390_7734" x1="46.7781" y1="195.74" x2="148.612" y2="195.74" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint10_linear_6390_7734" x1="126.493" y1="167.979" x2="136.461" y2="167.979" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint11_linear_6390_7734" x1="115.26" y1="238.494" x2="159.587" y2="238.494" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint12_linear_6390_7734" x1="155.519" y1="212.635" x2="169.801" y2="212.635" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint13_linear_6390_7734" x1="72.7002" y1="163.886" x2="100.504" y2="163.886" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint14_linear_6390_7734" x1="114.01" y1="187.672" x2="124.115" y2="187.672" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint15_linear_6390_7734" x1="101.724" y1="188.457" x2="111.687" y2="188.457" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint16_linear_6390_7734" x1="102.851" y1="232.82" x2="112.402" y2="232.82" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint17_linear_6390_7734" x1="155.519" y1="206.508" x2="169.801" y2="206.508" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint18_linear_6390_7734" x1="116.3" y1="218.983" x2="125.85" y2="218.983" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint19_linear_6390_7734" x1="113.686" y1="207.114" x2="126.952" y2="207.114" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFAE00"/>
<stop offset="1" stop-color="#FF7800"/>
</linearGradient>
<linearGradient id="paint20_linear_6390_7734" x1="222.527" y1="166.394" x2="290.676" y2="166.394" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint21_linear_6390_7734" x1="159.21" y1="103.211" x2="172.514" y2="103.211" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D3DBEB"/>
</linearGradient>
<linearGradient id="paint22_linear_6390_7734" x1="158.858" y1="103.394" x2="173.073" y2="103.394" gradientUnits="userSpaceOnUse">
<stop stop-color="#6A6AE8"/>
<stop offset="1" stop-color="#312890"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.0007 2.5C15.9687 2.5 20.0007 6.532 20.0007 11.5C20.0007 16.468 15.9687 20.5 11.0007 20.5C6.03267 20.5 2.00067 16.468 2.00067 11.5C2.00067 6.532 6.03267 2.5 11.0007 2.5ZM11.0007 18.5C14.8677 18.5 18.0007 15.367 18.0007 11.5C18.0007 7.632 14.8677 4.5 11.0007 4.5C7.13267 4.5 4.00067 7.632 4.00067 11.5C4.00067 15.367 7.13267 18.5 11.0007 18.5ZM19.4857 18.571L22.3147 21.399L20.8997 22.814L18.0717 19.985L19.4857 18.571Z" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 552 B

View File

@ -1,3 +1,5 @@
// lib/core/config/api_config.dart
class ApiConfig { class ApiConfig {
// Private constructor to prevent instantiation // Private constructor to prevent instantiation
ApiConfig._(); ApiConfig._();
@ -35,4 +37,16 @@ class ApiConfig {
/// Headers: {'Authorization': 'Bearer <token>'} /// Headers: {'Authorization': 'Bearer <token>'}
static const String addDiscount = '$baseUrl/discount/add'; static const String addDiscount = '$baseUrl/discount/add';
static const String getDiscounts = '$baseUrl/discount/get'; static const String getDiscounts = '$baseUrl/discount/get';
} static const String getActiveDiscounts = '$baseUrl/discount/get?status=1';
/// Endpoint to get a single discount by its ID.
/// Method: GET
/// Headers: {'Authorization': 'Bearer <token>'}
static String getDiscountById(String id) => '$baseUrl/discount/get/$id';
/// Endpoint to edit an existing discount.
/// Method: POST
/// Body: FormData
/// Headers: {'Authorization': 'Bearer <token>'}
static String editDiscount(String id) => '$baseUrl/discount/edit/$id';
}

View File

@ -1,3 +1,5 @@
// lib/domain/entities/discount_entity.dart
class DiscountEntity { class DiscountEntity {
final String id; final String id;
final String name; final String name;
@ -29,19 +31,23 @@ class DiscountEntity {
} }
return []; return [];
} }
return DiscountEntity( return DiscountEntity(
id: json['_id'] ?? '', // --- FIX IS HERE: Reading "ID" instead of "_id" ---
id: json['ID'] ?? '', // Changed from '_id' to 'ID'
name: json['Name'] ?? 'بدون نام', name: json['Name'] ?? 'بدون نام',
// Safely access nested properties // Safely access nested properties
shopName: (json['Shop'] != null ? json['Shop']['Name'] : 'فروشگاه') ?? 'فروشگاه', shopName:
(json['Shop'] != null ? json['Shop']['Name'] : 'فروشگاه') ?? 'فروشگاه',
images: _parseImages(json['Images']), images: _parseImages(json['Images']),
type: (json['Type'] != null ? json['Type']['Description'] : 'عمومی') ?? 'عمومی', type: (json['Type'] != null ? json['Type']['Description'] : 'عمومی') ??
'عمومی',
description: json['Description'] ?? '', description: json['Description'] ?? '',
price: (json['Price'] as num? ?? 0).toDouble(), price: (json['Price'] as num? ?? 0).toDouble(),
nPrice: (json['NPrice'] as num? ?? 0).toDouble(), nPrice: (json['NPrice'] as num? ?? 0).toDouble(),
// Handle potential null or invalid date // Handle potential null or invalid date
endDate: json['EndDate'] != null ? DateTime.tryParse(json['EndDate']) : null, endDate:
json['EndDate'] != null ? DateTime.tryParse(json['EndDate']) : null,
); );
} }
} }

View File

@ -129,6 +129,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/edit.svg /// File path: assets/icons/edit.svg
String get edit => 'assets/icons/edit.svg'; String get edit => 'assets/icons/edit.svg';
/// File path: assets/icons/empty_home.svg
String get emptyHome => 'assets/icons/empty_home.svg';
/// File path: assets/icons/error.svg /// File path: assets/icons/error.svg
String get error => 'assets/icons/error.svg'; String get error => 'assets/icons/error.svg';
@ -171,6 +174,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/resturan.svg /// File path: assets/icons/resturan.svg
String get resturan => 'assets/icons/resturan.svg'; String get resturan => 'assets/icons/resturan.svg';
/// File path: assets/icons/ri_search-2-line.svg
String get riSearch2Line => 'assets/icons/ri_search-2-line.svg';
/// File path: assets/icons/routing.svg /// File path: assets/icons/routing.svg
String get routing => 'assets/icons/routing.svg'; String get routing => 'assets/icons/routing.svg';
@ -266,6 +272,7 @@ class $AssetsIconsGen {
documentText, documentText,
edit02, edit02,
edit, edit,
emptyHome,
error, error,
fastfood, fastfood,
galleryAdd, galleryAdd,
@ -280,6 +287,7 @@ class $AssetsIconsGen {
radar2, radar2,
receiptDisscount, receiptDisscount,
resturan, resturan,
riSearch2Line,
routing, routing,
scanBarcode, scanBarcode,
shop, shop,

View File

@ -1,9 +1,10 @@
import 'package:business_panel/core/config/app_colors.dart'; import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/presentation/auth/bloc/auth_bloc.dart'; import 'package:business_panel/presentation/auth/bloc/auth_bloc.dart';
import 'package:business_panel/presentation/pages/onboarding_page.dart'; import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/splash_page.dart'; import 'package:business_panel/presentation/pages/splash_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:persian_datetime_picker/persian_datetime_picker.dart'; import 'package:persian_datetime_picker/persian_datetime_picker.dart';
@ -16,8 +17,13 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return MultiBlocProvider(
create: (context) => AuthBloc(), providers: [
BlocProvider(create: (context) => AuthBloc()),
BlocProvider(
create: (context) => HomeBloc()..add(FetchDiscounts()),
),
],
child: MaterialApp( child: MaterialApp(
title: 'Proxibuy', title: 'Proxibuy',
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
@ -29,9 +35,9 @@ class MyApp extends StatelessWidget {
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
], ],
supportedLocales: const [ supportedLocales: const [
Locale("fa", "IR"), Locale("fa", "IR"),
Locale("en", "US"), Locale("en", "US"),
], ],
locale: const Locale("fa", "IR"), locale: const Locale("fa", "IR"),
theme: ThemeData( theme: ThemeData(
fontFamily: 'Dana', fontFamily: 'Dana',
@ -104,5 +110,4 @@ class MyApp extends StatelessWidget {
), ),
); );
} }
} }

View File

@ -1,5 +1,6 @@
import 'dart:io'; // کتابخانه برای SocketException اضافه شد
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:business_panel/core/config/api_config.dart'; // <-- این خط را اضافه کنید import 'package:business_panel/core/config/api_config.dart';
import 'package:business_panel/core/services/token_storage_service.dart'; import 'package:business_panel/core/services/token_storage_service.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:business_panel/core/utils/logging_interceptor.dart'; import 'package:business_panel/core/utils/logging_interceptor.dart';
@ -29,18 +30,26 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
return; return;
} }
// Use the ApiConfig class
await _dio.get( await _dio.get(
ApiConfig.checkShopStatus, // <-- تغییر در این خط ApiConfig.checkShopStatus,
options: Options( options: Options(
headers: {'Authorization': 'Bearer $token'}, headers: {'Authorization': 'Bearer $token'},
), ),
); );
emit(ShopExists()); emit(ShopExists());
} on DioException catch (e) { } on DioException catch (e) {
if (e.response?.statusCode == 404) { // --- منطق تشخیص آفلاین بودن بهبود یافت ---
final isOffline = e.error is SocketException ||
e.type == DioExceptionType.connectionError ||
e.type == DioExceptionType.sendTimeout ||
e.type == DioExceptionType.receiveTimeout;
if (isOffline) {
// اگر کاربر آفلاین باشد، این حالت صادر میشود
emit(AuthOffline());
} else if (e.response?.statusCode == 404) {
emit(NoShop()); emit(NoShop());
} else { } else {
emit(AuthFailure(e.response?.data?['message'] ?? 'An error occurred while checking shop status.')); emit(AuthFailure(e.response?.data?['message'] ?? 'An error occurred while checking shop status.'));
@ -53,9 +62,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
on<SendOTPEvent>((event, emit) async { on<SendOTPEvent>((event, emit) async {
emit(AuthLoading()); emit(AuthLoading());
try { try {
// Use the ApiConfig class
final response = await _dio.post( final response = await _dio.post(
ApiConfig.sendOtp, // <-- تغییر در این خط ApiConfig.sendOtp,
data: {'Phone': event.phoneNumber, 'Code': event.countryCode}, data: {'Phone': event.phoneNumber, 'Code': event.countryCode},
); );
@ -72,9 +80,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
on<VerifyOTPEvent>((event, emit) async { on<VerifyOTPEvent>((event, emit) async {
emit(AuthLoading()); emit(AuthLoading());
try { try {
// Use the ApiConfig class
final response = await _dio.post( final response = await _dio.post(
ApiConfig.verifyOtp, // <-- تغییر در این خط ApiConfig.verifyOtp,
data: { data: {
'Phone': event.phoneNumber, 'Phone': event.phoneNumber,
'Code': event.countryCode, 'Code': event.countryCode,

View File

@ -18,6 +18,10 @@ class ShopExists extends AuthState {}
// ADDED: State for when the user is logged in but has no shop // ADDED: State for when the user is logged in but has no shop
class NoShop extends AuthState {} class NoShop extends AuthState {}
// *** CHANGE IS HERE: Added state for offline mode ***
// ADDED: State for when the user is authenticated but offline
class AuthOffline extends AuthState {}
class AuthCodeSentSuccess extends AuthState {} class AuthCodeSentSuccess extends AuthState {}
class AuthVerified extends AuthState {} class AuthVerified extends AuthState {}

View File

@ -1,23 +1,114 @@
// lib/presentation/discount/bloc/discount_bloc.dart
import 'dart:developer';
import 'package:business_panel/core/config/api_config.dart'; import 'package:business_panel/core/config/api_config.dart';
import 'package:business_panel/core/services/token_storage_service.dart'; import 'package:business_panel/core/services/token_storage_service.dart';
import 'package:business_panel/core/utils/logging_interceptor.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'discount_event.dart'; import 'discount_event.dart';
import 'discount_state.dart'; import 'discount_state.dart';
import 'dart:convert'; // Import for jsonEncode
class DiscountBloc extends Bloc<DiscountEvent, DiscountState> { class DiscountBloc extends Bloc<DiscountEvent, DiscountState> {
final Dio _dio = Dio();
final TokenStorageService _tokenStorage = TokenStorageService();
DiscountBloc() : super(const DiscountState()) { DiscountBloc() : super(const DiscountState()) {
_dio.interceptors.add(LoggingInterceptor());
final Dio _dio = Dio();
final TokenStorageService _tokenStorage = TokenStorageService(); on<FetchDiscountDetails>((event, emit) async {
emit(state.copyWith(isLoadingDetails: true, errorMessage: null));
try {
final token = await _tokenStorage.getAccessToken();
if (token == null) {
emit(
state.copyWith(
isLoadingDetails: false,
errorMessage: "خطای احراز هویت.",
),
);
return;
}
final response = await _dio.get(
ApiConfig.getDiscountById(event.discountId),
options: Options(headers: {'Authorization': 'Bearer $token'}),
);
if (response.statusCode == 200 && response.data['data'] != null) {
final data = response.data['data'];
List<Map<String, String?>> images = [];
if (data['Images'] is List) {
images = (data['Images'] as List)
.map<Map<String, String?>>(
(img) => {
'id': img['_id'] as String?,
'url': img['Url'] as String?,
},
)
.where((img) => img['url'] != null)
.toList();
}
final name = data['Name'] ?? '';
final typeId = data['Type']?['ID'];
final description = data['Description'] ?? '';
final price = data['Price']?.toString() ?? '0';
final nPrice = data['NPrice']?.toString() ?? '0';
final startDate =
data['StartDate'] != null ? DateTime.tryParse(data['StartDate']) : null;
final endDate =
data['EndDate'] != null ? DateTime.tryParse(data['EndDate']) : null;
final startTime = data['StartTime'];
final endTime = data['EndTime'];
final radius = (data['Radius'] as num?)?.toDouble() ?? 0.0;
emit(
state.copyWith(
isLoadingDetails: false,
discountId: data['_id'],
productName: name,
productImages: images,
discountTypeId: typeId,
description: description,
price: price,
discountedPrice: nPrice,
startDate: startDate,
endDate: endDate,
startTime: startTime,
endTime: endTime,
notificationRadius: radius,
),
);
} else {
emit(
state.copyWith(
isLoadingDetails: false,
errorMessage: "تخفیف یافت نشد.",
),
);
}
} catch (e) {
emit(
state.copyWith(
isLoadingDetails: false,
errorMessage: 'خطا در دریافت اطلاعات.',
),
);
}
});
on<ProductImageAdded>((event, emit) { on<ProductImageAdded>((event, emit) {
List<String> updatedImages = List.from(state.productImages); List<Map<String, String?>> updatedImages = List.from(state.productImages);
final newImageMap = {'id': null, 'url': event.imagePath};
if (updatedImages.length > event.index) { if (updatedImages.length > event.index) {
updatedImages[event.index] = event.imagePath; updatedImages[event.index] = newImageMap;
} else { } else {
updatedImages.add(event.imagePath); updatedImages.add(newImageMap);
} }
emit(state.copyWith(productImages: updatedImages)); emit(state.copyWith(productImages: updatedImages));
}); });
@ -55,57 +146,99 @@ class DiscountBloc extends Bloc<DiscountEvent, DiscountState> {
}); });
on<SubmitDiscount>((event, emit) async { on<SubmitDiscount>((event, emit) async {
emit(state.copyWith(isSubmitting: true, errorMessage: null)); await _submitDiscountForm(emit, isEdit: false);
});
try { on<UpdateDiscount>((event, emit) async {
final token = await _tokenStorage.getAccessToken(); await _submitDiscountForm(
if (token == null) { emit,
emit(state.copyWith(isSubmitting: false, errorMessage: "خطای احراز هویت.")); isEdit: true,
return; discountId: event.discountId,
} );
List<MultipartFile> imageFiles = [];
for (var imagePath in state.productImages) {
imageFiles.add(await MultipartFile.fromFile(
imagePath,
filename: imagePath.split('/').last,
));
}
final data = {
'Name' : state.productName,
'Images': imageFiles,
'Type': state.discountTypeId,
'Description': state.description,
'Price': double.tryParse(state.price),
'NPrice': double.tryParse(state.discountedPrice),
'Start': state.startDate != null ? DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(state.startDate!) : null,
'End': state.endDate != null ? DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(state.endDate!) : null,
'StartTime': state.startTime,
'EndTime': state.endTime,
'Radius': state.notificationRadius,
};
final formData = FormData.fromMap(data);
await _dio.post(
ApiConfig.addDiscount,
data: formData,
options: Options(
headers: {'Authorization': 'Bearer $token'},
),
);
emit(state.copyWith(isSubmitting: false, isSuccess: true));
} on DioException catch (e) {
emit(state.copyWith(
isSubmitting: false,
errorMessage: e.response?.data['message'] ?? 'خطای سرور.',
));
} catch (e) {
emit(state.copyWith(isSubmitting: false, errorMessage: 'خطای ناشناخته: ${e.toString()}'));
}
}); });
} }
}
Future<void> _submitDiscountForm(
Emitter<DiscountState> emit, {
required bool isEdit,
String? discountId,
}) async {
emit(state.copyWith(isSubmitting: true, errorMessage: null));
try {
final token = await _tokenStorage.getAccessToken();
if (token == null) {
emit(
state.copyWith(isSubmitting: false, errorMessage: "خطای احراز هویت."),
);
return;
}
final Map<String, dynamic> data = {
'Name': state.productName,
'Type': state.discountTypeId,
'Description': state.description,
'Price': double.tryParse(state.price),
'NPrice': double.tryParse(state.discountedPrice),
'Start': state.startDate?.toUtc().toIso8601String(),
'End': state.endDate?.toUtc().toIso8601String(),
'StartTime': state.startTime,
'EndTime': state.endTime,
'Radius': state.notificationRadius,
};
List<MultipartFile> newImageFiles = [];
List<String> existingImageIds = [];
for (var imageMap in state.productImages) {
final id = imageMap['id'];
final url = imageMap['url'];
if (id != null && url != null && url.startsWith('http')) {
existingImageIds.add(id);
} else if (url != null && !url.startsWith('http')) {
newImageFiles.add(
await MultipartFile.fromFile(url, filename: url.split('/').last),
);
}
}
if (newImageFiles.isNotEmpty) {
data['Images'] = newImageFiles;
}
if (isEdit) {
data['ExistingImages'] = jsonEncode(existingImageIds);
}
// *** CHANGE IS HERE: Logging the data before sending ***
log('Submitting Discount Data: $data', name: 'DiscountBloc');
final formData = FormData.fromMap(data);
final url =
isEdit ? ApiConfig.editDiscount(discountId!) : ApiConfig.addDiscount;
await _dio.post(
url,
data: formData,
options: Options(headers: {'Authorization': 'Bearer $token'}),
);
emit(state.copyWith(isSubmitting: false, isSuccess: true));
} on DioException catch (e) {
emit(
state.copyWith(
isSubmitting: false,
errorMessage: e.response?.data['message'] ?? 'خطای سرور.',
),
);
} catch (e) {
emit(
state.copyWith(
isSubmitting: false,
errorMessage: 'خطای ناشناخته: ${e.toString()}',
),
);
}
}
}

View File

@ -1,6 +1,13 @@
// lib/presentation/discount/bloc/discount_event.dart
abstract class DiscountEvent {} abstract class DiscountEvent {}
// Fetch details for editing
class FetchDiscountDetails extends DiscountEvent {
final String discountId;
FetchDiscountDetails(this.discountId);
}
class ProductImageAdded extends DiscountEvent { class ProductImageAdded extends DiscountEvent {
final String imagePath; final String imagePath;
final int index; final int index;
@ -15,7 +22,7 @@ class ProductNameChanged extends DiscountEvent {
class DiscountTypeChanged extends DiscountEvent { class DiscountTypeChanged extends DiscountEvent {
final String typeId; final String typeId;
DiscountTypeChanged(this.typeId); DiscountTypeChanged(this.typeId);
} }
class DescriptionChanged extends DiscountEvent { class DescriptionChanged extends DiscountEvent {
final String description; final String description;
@ -49,4 +56,10 @@ class NotificationRadiusChanged extends DiscountEvent {
NotificationRadiusChanged(this.radius); NotificationRadiusChanged(this.radius);
} }
class SubmitDiscount extends DiscountEvent {} class SubmitDiscount extends DiscountEvent {}
// Event for updating an existing discount
class UpdateDiscount extends DiscountEvent {
final String discountId;
UpdateDiscount(this.discountId);
}

View File

@ -1,22 +1,28 @@
// lib/presentation/discount/bloc/discount_state.dart
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
class DiscountState extends Equatable { class DiscountState extends Equatable {
final List<String> productImages; final String? discountId;
// *** CHANGE IS HERE: Storing image ID and URL together ***
final List<Map<String, String?>> productImages;
final String productName; final String productName;
final String? discountTypeId; final String? discountTypeId;
final String description; final String description;
final DateTime? startDate; final DateTime? startDate;
final DateTime? endDate; final DateTime? endDate;
final String? startTime; final String? startTime;
final String? endTime; final String? endTime;
final String price; final String price;
final String discountedPrice; final String discountedPrice;
final double notificationRadius; final double notificationRadius;
final bool isSubmitting; final bool isSubmitting;
final bool isLoadingDetails;
final bool isSuccess; final bool isSuccess;
final String? errorMessage; final String? errorMessage;
const DiscountState({ const DiscountState({
this.discountId,
this.productImages = const [], this.productImages = const [],
this.productName = '', this.productName = '',
this.discountTypeId, this.discountTypeId,
@ -29,12 +35,14 @@ class DiscountState extends Equatable {
this.discountedPrice = '', this.discountedPrice = '',
this.notificationRadius = 0.0, this.notificationRadius = 0.0,
this.isSubmitting = false, this.isSubmitting = false,
this.isLoadingDetails = false,
this.isSuccess = false, this.isSuccess = false,
this.errorMessage, this.errorMessage,
}); });
DiscountState copyWith({ DiscountState copyWith({
List<String>? productImages, String? discountId,
List<Map<String, String?>>? productImages,
String? productName, String? productName,
String? discountTypeId, String? discountTypeId,
String? description, String? description,
@ -46,10 +54,12 @@ class DiscountState extends Equatable {
String? discountedPrice, String? discountedPrice,
double? notificationRadius, double? notificationRadius,
bool? isSubmitting, bool? isSubmitting,
bool? isLoadingDetails,
bool? isSuccess, bool? isSuccess,
String? errorMessage, String? errorMessage,
}) { }) {
return DiscountState( return DiscountState(
discountId: discountId ?? this.discountId,
productImages: productImages ?? this.productImages, productImages: productImages ?? this.productImages,
productName: productName ?? this.productName, productName: productName ?? this.productName,
discountTypeId: discountTypeId ?? this.discountTypeId, discountTypeId: discountTypeId ?? this.discountTypeId,
@ -62,6 +72,7 @@ class DiscountState extends Equatable {
discountedPrice: discountedPrice ?? this.discountedPrice, discountedPrice: discountedPrice ?? this.discountedPrice,
notificationRadius: notificationRadius ?? this.notificationRadius, notificationRadius: notificationRadius ?? this.notificationRadius,
isSubmitting: isSubmitting ?? this.isSubmitting, isSubmitting: isSubmitting ?? this.isSubmitting,
isLoadingDetails: isLoadingDetails ?? this.isLoadingDetails,
isSuccess: isSuccess ?? this.isSuccess, isSuccess: isSuccess ?? this.isSuccess,
errorMessage: errorMessage ?? this.errorMessage, errorMessage: errorMessage ?? this.errorMessage,
); );
@ -69,6 +80,7 @@ class DiscountState extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
discountId,
productImages, productImages,
productName, productName,
discountTypeId, discountTypeId,
@ -81,6 +93,7 @@ class DiscountState extends Equatable {
discountedPrice, discountedPrice,
notificationRadius, notificationRadius,
isSubmitting, isSubmitting,
isLoadingDetails,
isSuccess, isSuccess,
errorMessage, errorMessage,
]; ];

View File

@ -1,6 +1,7 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:business_panel/core/config/api_config.dart'; import 'package:business_panel/core/config/api_config.dart';
import 'package:business_panel/core/services/token_storage_service.dart'; import 'package:business_panel/core/services/token_storage_service.dart';
import 'package:business_panel/core/utils/logging_interceptor.dart';
import 'package:business_panel/domain/entities/discount_entity.dart'; import 'package:business_panel/domain/entities/discount_entity.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -13,43 +14,57 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
final TokenStorageService _tokenStorage = TokenStorageService(); final TokenStorageService _tokenStorage = TokenStorageService();
HomeBloc() : super(HomeInitial()) { HomeBloc() : super(HomeInitial()) {
_dio.interceptors.add(LoggingInterceptor());
on<FetchDiscounts>((event, emit) async { on<FetchDiscounts>((event, emit) async {
emit(HomeLoading()); await _fetchDiscounts(emit);
try { });
final token = await _tokenStorage.getAccessToken();
if (token == null || token.isEmpty) {
emit(HomeError("خطای احراز هویت. لطفا دوباره وارد شوید."));
return;
}
final response = await _dio.get( on<SearchDiscounts>((event, emit) async {
ApiConfig.getDiscounts, await _fetchDiscounts(emit, searchQuery: event.query);
options: Options(
headers: {'Authorization': 'Bearer $token'},
),
);
if (response.statusCode == 200 && response.data['data'] != null) {
final List<dynamic> data = response.data['data'];
final discounts = data.map((json) => DiscountEntity.fromJson(json)).toList();
emit(HomeLoaded(discounts));
} else {
emit(HomeError(response.data['message'] ?? 'خطا در دریافت اطلاعات'));
}
} on DioException catch (e) {
// Log Dio error
if (kDebugMode) {
print('DioException in HomeBloc: ${e.response?.data}');
}
emit(HomeError(e.response?.data['message'] ?? 'خطای شبکه'));
} catch (e, stackTrace) {
// Log any other error
if (kDebugMode) {
print('Error in HomeBloc: $e');
print(stackTrace);
}
emit(HomeError('خطای پیش‌بینی نشده رخ داد: ${e.toString()}'));
}
}); });
} }
Future<void> _fetchDiscounts(Emitter<HomeState> emit, {String? searchQuery}) async {
emit(HomeLoading());
try {
final token = await _tokenStorage.getAccessToken();
if (token == null || token.isEmpty) {
emit(HomeError("خطای احراز هویت. لطفا دوباره وارد شوید."));
return;
}
String url = ApiConfig.getActiveDiscounts;
if (searchQuery != null && searchQuery.isNotEmpty) {
url = '$url&search=$searchQuery';
}
final response = await _dio.get(
url,
options: Options(
headers: {'Authorization': 'Bearer $token'},
),
);
if (response.statusCode == 200 && response.data['data'] != null) {
final List<dynamic> data = response.data['data']['discounts'] ?? [];
final discounts =
data.map((json) => DiscountEntity.fromJson(json)).toList();
emit(HomeLoaded(discounts));
} else {
emit(HomeError(response.data['message'] ?? 'خطا در دریافت اطلاعات'));
}
} on DioException catch (e) {
if (kDebugMode) {
print('DioException in HomeBloc: ${e.response?.data}');
}
emit(HomeError(e.response?.data['message'] ?? 'خطای شبکه'));
} catch (e, stackTrace) {
if (kDebugMode) {
print('Error in HomeBloc: $e');
print(stackTrace);
}
emit(HomeError('خطای پیش‌بینی نشده رخ داد: ${e.toString()}'));
}
}
} }

View File

@ -2,4 +2,10 @@ part of 'home_bloc.dart';
abstract class HomeEvent {} abstract class HomeEvent {}
class FetchDiscounts extends HomeEvent {} class FetchDiscounts extends HomeEvent {}
class SearchDiscounts extends HomeEvent {
final String query;
SearchDiscounts({required this.query});
}

View File

@ -13,19 +13,29 @@ import 'package:image_picker/image_picker.dart';
import 'package:persian_datetime_picker/persian_datetime_picker.dart'; import 'package:persian_datetime_picker/persian_datetime_picker.dart';
class AddDiscountPage extends StatelessWidget { class AddDiscountPage extends StatelessWidget {
const AddDiscountPage({super.key}); final String? discountId;
const AddDiscountPage({super.key, this.discountId});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (_) => DiscountBloc(), create: (context) {
child: const _AddDiscountView(), final bloc = DiscountBloc();
if (discountId != null) {
bloc.add(FetchDiscountDetails(discountId!));
}
return bloc;
},
child: _AddDiscountView(discountId: discountId),
); );
} }
} }
class _AddDiscountView extends StatefulWidget { class _AddDiscountView extends StatefulWidget {
const _AddDiscountView(); final String? discountId;
const _AddDiscountView({this.discountId});
@override @override
State<_AddDiscountView> createState() => _AddDiscountViewState(); State<_AddDiscountView> createState() => _AddDiscountViewState();
@ -37,6 +47,8 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
final _priceController = TextEditingController(); final _priceController = TextEditingController();
final _discountPriceController = TextEditingController(); final _discountPriceController = TextEditingController();
bool get _isEditMode => widget.discountId != null;
@override @override
void dispose() { void dispose() {
_nameController.dispose(); _nameController.dispose();
@ -83,8 +95,8 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
); );
context.read<DiscountBloc>().add( context.read<DiscountBloc>().add(
ValidityDateChanged(startDate: startDateTime, endDate: endDateTime), ValidityDateChanged(startDate: startDateTime, endDate: endDateTime),
); );
} }
final List<DiscountTypeEntity> discountTypes = [ final List<DiscountTypeEntity> discountTypes = [
@ -102,117 +114,131 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildCustomAppBar(context), appBar: _buildCustomAppBar(context),
body: BlocListener<DiscountBloc, DiscountState>( body: BlocConsumer<DiscountBloc, DiscountState>(
listener: (context, state) { listener: (context, state) {
if (state.isSuccess) { if (state.isSuccess) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("تخفیف با موفقیت ثبت شد!"), backgroundColor: Colors.green), SnackBar(
content: Text(
"تخفیف با موفقیت ${this._isEditMode ? 'ویرایش' : 'ثبت'} شد!"),
backgroundColor: Colors.green),
); );
// میتوانید به صفحه دیگری ناوبری کنید Navigator.of(context).pop(true);
// Navigator.of(context).pop();
} }
if (state.errorMessage != null) { if (state.errorMessage != null && !state.isLoadingDetails) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.errorMessage!), backgroundColor: Colors.red), SnackBar(
content: Text(state.errorMessage!), backgroundColor: Colors.red),
); );
} }
if (state.productName.isNotEmpty && _nameController.text.isEmpty) {
_nameController.text = state.productName;
_descController.text = state.description;
_priceController.text = state.price;
_discountPriceController.text = state.discountedPrice;
}
}, },
child: SingleChildScrollView( builder: (context, state) {
padding: const EdgeInsets.all(24), if (state.isLoadingDetails) {
child: Column( return const Center(child: CircularProgressIndicator());
crossAxisAlignment: CrossAxisAlignment.start, }
children: [ return SingleChildScrollView(
const Text( padding: const EdgeInsets.all(24),
"تعریف تخفیف جدید", child: Column(
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), crossAxisAlignment: CrossAxisAlignment.start,
), children: [
const SizedBox(height: 24), Text(
_buildSectionTitle( _isEditMode ? "ویرایش تخفیف" : "تعریف تخفیف جدید",
title: "بارگذاری عکس از محصول", style: const TextStyle(
popupTitle: "یه عکس خوب، یه فروش خوب‌تر!", fontWeight: FontWeight.bold, fontSize: 20),
isMandatory: true,
infoText:
"عکس واضح، باکیفیت و واقعی از محصولت بذار. ترجیحا از عکس‌های اینترنتی یا تبلیغاتی استفاده نکن.",
iconPath: Assets.icons.camera,
),
const SizedBox(height: 16),
_buildImagePickers(),
const SizedBox(height: 30),
_buildTextField(
controller: _nameController,
label: "نام محصول",
isRequired: true,
hint: "وافل شکلات فندقی",
onChanged:
(value) => context.read<DiscountBloc>().add(
ProductNameChanged(value),
),
),
const SizedBox(height: 30),
_buildDiscountTypeDropdown(),
const SizedBox(height: 30),
_buildTextField(
controller: _descController,
label: "توضیح برای تخفیف",
hint: "مثلاً عصرونه، با ۵٪ تخفیف مهمون ما باش! ",
isRequired: true,
maxLines: 4,
maxLength: 200,
onChanged:
(value) => context.read<DiscountBloc>().add(
DescriptionChanged(value),
),
),
const SizedBox(height: 30),
_buildDateTimePicker(),
const SizedBox(height: 30),
_buildTimeRangePicker(context),
const SizedBox(height: 30),
_buildTextField(
controller: _priceController,
label: "قیمت بدون تخفیف",
isRequired: true,
hint: "مثلاً 240000 تومان",
keyboardType: TextInputType.number,
onChanged:
(value) =>
context.read<DiscountBloc>().add(PriceChanged(value)),
),
const SizedBox(height: 30),
_buildTextField(
controller: _discountPriceController,
label: "قیمت با تخفیف",
hint: "مثلاً 200000 تومان",
isRequired: true,
keyboardType: TextInputType.number,
onChanged:
(value) => context.read<DiscountBloc>().add(
DiscountedPriceChanged(value),
),
),
const SizedBox(height: 30),
_buildNotificationRadiusSlider(),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
child: BlocBuilder<DiscountBloc, DiscountState>(
builder: (context, state) {
return ElevatedButton(
onPressed: state.isSubmitting ? null : () {
context.read<DiscountBloc>().add(SubmitDiscount());
},
child: state.isSubmitting
? const CircularProgressIndicator(color: Colors.white)
: const Text("ثبت تخفیف"),
);
},
), ),
), const SizedBox(height: 24),
const SizedBox(height: 30), _buildSectionTitle(
], title: "بارگذاری عکس از محصول",
), popupTitle: "یه عکس خوب، یه فروش خوب‌تر!",
isMandatory: !_isEditMode,
infoText:
"عکس واضح، باکیفیت و واقعی از محصولت بذار. ترجیحا از عکس‌های اینترنتی یا تبلیغاتی استفاده نکن.",
iconPath: Assets.icons.camera,
),
const SizedBox(height: 16),
_buildImagePickers(),
const SizedBox(height: 30),
_buildTextField(
controller: _nameController,
label: "نام محصول",
isRequired: true,
hint: "وافل شکلات فندقی",
onChanged: (value) =>
context.read<DiscountBloc>().add(ProductNameChanged(value)),
),
const SizedBox(height: 30),
_buildDiscountTypeDropdown(state), // Pass state here
const SizedBox(height: 30),
_buildTextField(
controller: _descController,
label: "توضیح برای تخفیف",
hint: "مثلاً عصرونه، با ۵٪ تخفیف مهمون ما باش! ",
isRequired: true,
maxLines: 4,
maxLength: 200,
onChanged: (value) =>
context.read<DiscountBloc>().add(DescriptionChanged(value)),
),
const SizedBox(height: 30),
_buildDateTimePicker(),
const SizedBox(height: 30),
_buildTimeRangePicker(context),
const SizedBox(height: 30),
_buildTextField(
controller: _priceController,
label: "قیمت بدون تخفیف",
isRequired: true,
hint: "مثلاً 240000 تومان",
keyboardType: TextInputType.number,
onChanged: (value) =>
context.read<DiscountBloc>().add(PriceChanged(value)),
),
const SizedBox(height: 30),
_buildTextField(
controller: _discountPriceController,
label: "قیمت با تخفیف",
hint: "مثلاً 200000 تومان",
isRequired: true,
keyboardType: TextInputType.number,
onChanged: (value) => context
.read<DiscountBloc>()
.add(DiscountedPriceChanged(value)),
),
const SizedBox(height: 30),
_buildNotificationRadiusSlider(),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: state.isSubmitting
? null
: () {
if (_isEditMode) {
context
.read<DiscountBloc>()
.add(UpdateDiscount(widget.discountId!));
} else {
context.read<DiscountBloc>().add(SubmitDiscount());
}
},
child: state.isSubmitting
? const CircularProgressIndicator(color: Colors.white)
: Text(_isEditMode ? "ثبت تغییرات" : "ثبت تخفیف"),
),
),
const SizedBox(height: 30),
],
),
);
},
), ),
)); );
} }
Widget _buildSectionTitle({ Widget _buildSectionTitle({
@ -227,13 +253,12 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
children: [ children: [
if (infoText != null && iconPath != null) if (infoText != null && iconPath != null)
IconButton( IconButton(
onPressed: onPressed: () => showInfoDialog(
() => showInfoDialog( context,
context, title: popupTitle ?? title,
title: popupTitle ?? title, content: infoText,
content: infoText, iconPath: iconPath,
iconPath: iconPath, ),
),
icon: SvgPicture.asset(Assets.icons.infoCircle, width: 17), icon: SvgPicture.asset(Assets.icons.infoCircle, width: 17),
), ),
Text( Text(
@ -248,24 +273,31 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
Widget _buildImagePickers() { Widget _buildImagePickers() {
return BlocBuilder<DiscountBloc, DiscountState>( return BlocBuilder<DiscountBloc, DiscountState>(
buildWhen: (p, c) => p.productImages != c.productImages,
builder: (context, state) { builder: (context, state) {
// We ensure the list has at least 2 elements for the UI, filling with null
final displayImages = List<Map<String, String?>?>.from(state.productImages);
while (displayImages.length < 2) {
displayImages.add(null);
}
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(2, (index) { children: List.generate(2, (index) {
final imagePath = // *** CHANGE IS HERE: Read from the map structure ***
state.productImages.length > index final imageMap = displayImages[index];
? state.productImages[index] final imageUrl = imageMap?['url'];
: null; final isUrl = imageUrl?.startsWith('http') ?? false;
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
final ImagePicker picker = ImagePicker(); final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage( final XFile? image =
source: ImageSource.gallery, await picker.pickImage(source: ImageSource.gallery, imageQuality: 80);
);
if (image != null && context.mounted) { if (image != null && context.mounted) {
context.read<DiscountBloc>().add( context
ProductImageAdded(image.path, index), .read<DiscountBloc>()
); .add(ProductImageAdded(image.path, index));
} }
}, },
child: Container( child: Container(
@ -275,23 +307,23 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
color: AppColors.uploadElevated, color: AppColors.uploadElevated,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.uploadElevated), border: Border.all(color: AppColors.uploadElevated),
image: image: imageUrl != null
imagePath != null ? DecorationImage(
? DecorationImage( image: isUrl
image: FileImage(File(imagePath)), ? NetworkImage(imageUrl)
fit: BoxFit.cover, : FileImage(File(imageUrl)) as ImageProvider,
) fit: BoxFit.cover,
: null,
),
child:
imagePath == null
? Center(
child: SvgPicture.asset(
Assets.icons.addPic,
width: 60,
),
) )
: null, : null,
),
child: imageUrl == null
? Center(
child: SvgPicture.asset(
Assets.icons.addPic,
width: 60,
),
)
: null,
), ),
); );
}), }),
@ -300,9 +332,17 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
); );
} }
Widget _buildDiscountTypeDropdown() { Widget _buildDiscountTypeDropdown(DiscountState state) {
// Create a set of available IDs for quick lookup.
final availableTypeIds = discountTypes.map((type) => type.id).toSet();
// Check if the current discount's type ID is in our list. If not, use null.
final String? selectedValue = availableTypeIds.contains(state.discountTypeId)
? state.discountTypeId
: null;
return DropdownButtonFormField<String>( return DropdownButtonFormField<String>(
value: context.watch<DiscountBloc>().state.discountTypeId, value: selectedValue, // Use the safe value here.
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.icons.arrowDown, Assets.icons.arrowDown,
width: 24, width: 24,
@ -328,7 +368,7 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
); );
} }
Widget _buildDateTimePicker() { Widget _buildDateTimePicker() {
return BlocBuilder<DiscountBloc, DiscountState>( return BlocBuilder<DiscountBloc, DiscountState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.startDate != current.startDate || previous.startDate != current.startDate ||
@ -336,7 +376,6 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
builder: (context, state) { builder: (context, state) {
String displayText = "انتخاب تاریخ"; String displayText = "انتخاب تاریخ";
if (state.startDate != null && state.endDate != null) { if (state.startDate != null && state.endDate != null) {
final jalaliStart = DateTimeExtensions(state.startDate!).toJalali(); final jalaliStart = DateTimeExtensions(state.startDate!).toJalali();
final jalaliEnd = DateTimeExtensions(state.endDate!).toJalali(); final jalaliEnd = DateTimeExtensions(state.endDate!).toJalali();
@ -361,7 +400,7 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
child: Text( child: Text(
displayText, displayText,
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
style: const TextStyle(fontSize: 15), // Optional: for better fit style: const TextStyle(fontSize: 15),
), ),
), ),
SvgPicture.asset(Assets.icons.calendarSearch), SvgPicture.asset(Assets.icons.calendarSearch),
@ -375,10 +414,9 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
Widget _buildTimeRangePicker(BuildContext context) { Widget _buildTimeRangePicker(BuildContext context) {
return BlocBuilder<DiscountBloc, DiscountState>( return BlocBuilder<DiscountBloc, DiscountState>(
buildWhen: buildWhen: (previous, current) =>
(previous, current) => previous.startTime != current.startTime ||
previous.startTime != current.startTime || previous.endTime != current.endTime,
previous.endTime != current.endTime,
builder: (context, state) { builder: (context, state) {
String displayText = "انتخاب بازه زمانی"; String displayText = "انتخاب بازه زمانی";
if (state.startTime != null && state.endTime != null) { if (state.startTime != null && state.endTime != null) {
@ -387,16 +425,12 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
return InkWell( return InkWell(
onTap: () async { onTap: () async {
final TimeOfDay? startTime = await showTimePicker( final TimeOfDay? startTime =
context: context, await showTimePicker(context: context, initialTime: TimeOfDay.now());
initialTime: TimeOfDay.now(),
);
if (startTime == null) return; if (startTime == null) return;
final TimeOfDay? endTime = await showTimePicker( final TimeOfDay? endTime =
context: context, await showTimePicker(context: context, initialTime: startTime);
initialTime: startTime,
);
if (endTime == null) return; if (endTime == null) return;
final formattedStartTime = final formattedStartTime =
@ -405,11 +439,9 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
'${endTime.hour.toString().padLeft(2, '0')}:${endTime.minute.toString().padLeft(2, '0')}'; '${endTime.hour.toString().padLeft(2, '0')}:${endTime.minute.toString().padLeft(2, '0')}';
context.read<DiscountBloc>().add( context.read<DiscountBloc>().add(
TimeRangeChanged( TimeRangeChanged(
startTime: formattedStartTime, startTime: formattedStartTime, endTime: formattedEndTime),
endTime: formattedEndTime, );
),
);
}, },
child: InputDecorator( child: InputDecorator(
decoration: _inputDecoration("بازه زمانی معتبر", isRequired: true), decoration: _inputDecoration("بازه زمانی معتبر", isRequired: true),
@ -430,22 +462,18 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
Row( Row(
children: [ children: [
IconButton( IconButton(
onPressed: onPressed: () => showInfoDialog(
() => showInfoDialog( context,
context, title: "انتخاب محدوده نمایش تخفیف",
title: "انتخاب محدوده نمایش تخفیف", content:
content: "محدوده‌ای رو مشخص کن که تخفیف‌هات فقط به کاربرانی که تو اون شعاع هستن نشون داده بشه.",
"محدوده‌ای رو مشخص کن که تخفیف‌هات فقط به کاربرانی که تو اون شعاع هستن نشون داده بشه.", iconPath: Assets.icons.radar2,
iconPath: Assets.icons.radar2, ),
),
icon: SvgPicture.asset(Assets.icons.infoCircle, width: 17), icon: SvgPicture.asset(Assets.icons.infoCircle, width: 17),
), ),
Text( const Text(
"شعاع ارسال اعلان تخفیف به مشتری‌ها", "شعاع ارسال اعلان تخفیف به مشتری‌ها",
style: const TextStyle( style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
fontWeight: FontWeight.bold,
fontSize: 14,
),
), ),
], ],
), ),
@ -462,13 +490,11 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
trackShape: const RoundedRectSliderTrackShape(), trackShape: const RoundedRectSliderTrackShape(),
trackHeight: 4.0, trackHeight: 4.0,
thumbColor: AppColors.active, thumbColor: AppColors.active,
thumbShape: const RoundSliderThumbShape( thumbShape:
enabledThumbRadius: 12.0, const RoundSliderThumbShape(enabledThumbRadius: 12.0),
),
overlayColor: AppColors.active.withAlpha(32), overlayColor: AppColors.active.withAlpha(32),
overlayShape: const RoundSliderOverlayShape( overlayShape:
overlayRadius: 28.0, const RoundSliderOverlayShape(overlayRadius: 28.0),
),
), ),
child: Slider( child: Slider(
value: state.notificationRadius, value: state.notificationRadius,
@ -477,24 +503,20 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
divisions: 100, divisions: 100,
label: '${state.notificationRadius.toInt()} متر', label: '${state.notificationRadius.toInt()} متر',
onChanged: (value) { onChanged: (value) {
context.read<DiscountBloc>().add( context
NotificationRadiusChanged(value), .read<DiscountBloc>()
); .add(NotificationRadiusChanged(value));
}, },
), ),
), ),
SizedBox(height: 7,), const SizedBox(height: 7),
BlocBuilder<DiscountBloc, DiscountState>( Text(
builder: (context, state) { '${state.notificationRadius.toInt()} متر',
return Text( style: const TextStyle(
'${state.notificationRadius.toInt()} متر', fontWeight: FontWeight.normal,
style: const TextStyle( fontSize: 14,
fontWeight: FontWeight.normal, color: Colors.black,
fontSize: 14, ),
color: Colors.black,
),
);
},
), ),
], ],
); );
@ -523,36 +545,26 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
maxLines: maxLines, maxLines: maxLines,
maxLength: maxLength, maxLength: maxLength,
keyboardType: keyboardType, keyboardType: keyboardType,
decoration: _inputDecoration( decoration: _inputDecoration(label, hint: hint, isRequired: isRequired)
label, .copyWith(
hint: hint,
isRequired: isRequired,
).copyWith(
counterText: '', counterText: '',
counter: counter: maxLength != null
maxLength != null ? Text(
? Text( '${value.text.length}/$maxLength',
'${value.text.length}/$maxLength', style: Theme.of(context).textTheme.bodySmall,
style: Theme.of(context).textTheme.bodySmall, )
) : null,
: null,
), ),
); );
}, },
); );
} }
InputDecoration _inputDecoration( InputDecoration _inputDecoration(String label,
String label, { {String? hint, bool isRequired = false}) {
String? hint,
bool isRequired = false,
}) {
return InputDecoration( return InputDecoration(
hintText: hint, hintText: hint,
hintStyle: TextStyle( hintStyle: const TextStyle(color: Color.fromARGB(255, 95, 95, 95), fontSize: 14),
color: Color.fromARGB(255, 95, 95, 95),
fontSize: 14,
),
label: RichText( label: RichText(
text: TextSpan( text: TextSpan(
text: label, text: label,
@ -564,7 +576,8 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
), ),
children: [ children: [
if (isRequired) if (isRequired)
const TextSpan(text: ' *', style: TextStyle(color: Colors.red)), const TextSpan(
text: ' *', style: TextStyle(color: Colors.red)),
], ],
), ),
), ),
@ -577,9 +590,7 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)),
bottom: Radius.circular(15),
),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.08), color: Colors.black.withOpacity(0.08),
@ -591,30 +602,19 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
child: SafeArea( child: SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0), padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const SizedBox(height: 15), SvgPicture.asset(Assets.icons.logoWithName),
Row( Row(
children: [ children: [
Padding( IconButton(
padding: const EdgeInsets.only(right: 8), onPressed: () {},
child: SvgPicture.asset(Assets.icons.logoWithName), icon: SvgPicture.asset(Assets.icons.discountShape, color: Colors.black),
), ),
const Spacer(), IconButton(
Row( onPressed: () {},
children: [ icon: SvgPicture.asset(Assets.icons.scanBarcode),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
), ),
], ],
), ),
@ -625,4 +625,4 @@ class _AddDiscountViewState extends State<_AddDiscountView> {
), ),
); );
} }
} }

View File

@ -0,0 +1,116 @@
import 'dart:async'; // اضافه کردن کتابخانه برای استفاده از Timer
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/widgets/active_discount_card.dart';
import 'package:business_panel/presentation/widgets/custom_app_bar_single.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:business_panel/gen/assets.gen.dart';
class DiscountManegment extends StatefulWidget {
const DiscountManegment({super.key});
@override
State<DiscountManegment> createState() => _DiscountManegmentState();
}
class _DiscountManegmentState extends State<DiscountManegment> {
final TextEditingController _searchController = TextEditingController();
Timer? _debounce;
@override
void initState() {
super.initState();
// Fetch initial discounts when the page loads
// Note: Using addPostFrameCallback to ensure context is available
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
context.read<HomeBloc>().add(FetchDiscounts());
}
});
}
@override
void dispose() {
_searchController.dispose();
_debounce?.cancel(); // کنسل کردن تایمر برای جلوگیری از نشت حافظه
super.dispose();
}
void _onSearchChanged(String query) {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
if (mounted) {
context.read<HomeBloc>().add(SearchDiscounts(query: query));
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBarSingle(
page: "رزرو ها",
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'دنبال چی می‌گردی؟',
hintStyle: TextStyle(color: Color.fromARGB(255, 157, 157, 157)),
prefixIcon: Padding(
padding: const EdgeInsets.all(12.0),
child: SvgPicture.asset(
Assets.icons.riSearch2Line,
),
),
fillColor: Color.fromARGB(255, 244, 244, 244),
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(vertical: 0),
),
onChanged: _onSearchChanged, // استفاده از متد جدید
),
),
Expanded(
child: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
if (state is HomeError) {
return Center(child: Text('خطا: ${state.message}'));
}
if (state is HomeLoaded) {
if (state.discounts.isEmpty) {
return const Center(child: Text("هیچ تخفیفی با این مشخصات یافت نشد."));
}
return RefreshIndicator(
onRefresh: () async {
context.read<HomeBloc>().add(FetchDiscounts());
_searchController.clear();
},
child: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: state.discounts.length,
itemBuilder: (context, index) {
final discount = state.discounts[index];
return ActiveDiscountCard(discount: discount);
},
),
);
}
return const Center(child: CircularProgressIndicator());
},
),
),
],
),
);
}
}

View File

@ -1,36 +1,23 @@
import 'package:business_panel/core/config/app_colors.dart'; import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/domain/entities/discount_entity.dart';
import 'package:business_panel/gen/assets.gen.dart'; import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart'; import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
import 'package:business_panel/presentation/widgets/custom_app_bar.dart';
import 'package:business_panel/presentation/widgets/discount_card.dart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:slide_countdown/slide_countdown.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
class HomePage extends StatefulWidget { class HomePage extends StatelessWidget {
const HomePage({super.key}); const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
context.read<HomeBloc>().add(FetchDiscounts());
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildCustomAppBar(context), appBar: const CustomAppBar(),
body: BlocBuilder<HomeBloc, HomeState>( body: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) { builder: (context, state) {
if (state is HomeLoading) { // --- منطق اصلاحشده برای مدیریت وضعیت ---
return const Center(child: CircularProgressIndicator());
}
if (state is HomeError) { if (state is HomeError) {
return Center( return Center(
child: Padding( child: Padding(
@ -39,9 +26,10 @@ class _HomePageState extends State<HomePage> {
), ),
); );
} }
if (state is HomeLoaded) { if (state is HomeLoaded) {
if (state.discounts.isEmpty) { if (state.discounts.isEmpty) {
return _buildEmptyState(); return _buildEmptyState(context);
} }
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
@ -49,49 +37,50 @@ class _HomePageState extends State<HomePage> {
}, },
child: ListView.builder( child: ListView.builder(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
// تعداد آیتمها یکی بیشتر از تعداد تخفیفهاست تا دکمه هم جا شود
itemCount: state.discounts.length + 1, itemCount: state.discounts.length + 1,
itemBuilder: (context, index) { itemBuilder: (context, index) {
// اگر ایندکس مربوط به آخرین آیتم بود، دکمه را نمایش بده
if (index == state.discounts.length) { if (index == state.discounts.length) {
return _buildAddDiscountButton(); return _buildAddDiscountButton(context);
} }
// در غیر این صورت، کارت تخفیف را نمایش بده
final discount = state.discounts[index]; final discount = state.discounts[index];
return _buildDiscountCard(discount); return DiscountCard(discount: discount);
}, },
), ),
); );
} }
// حالت پیشفرض
return _buildEmptyState(); // برای حالتهای HomeInitial و HomeLoading
return const Center(child: CircularProgressIndicator());
}, },
), ),
); );
} }
Widget _buildEmptyState() { Widget _buildEmptyState(BuildContext context) {
return Center( return Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SvgPicture.asset(Assets.images.emptyHome, height: 200), SvgPicture.asset(Assets.icons.emptyHome, height: 300),
const SizedBox(height: 20), const SizedBox(height: 35),
const Text( const Text("سلام!", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17)),
"هنوز تخفیفی ثبت نکرده‌اید", const SizedBox(height: 15),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0), padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: _buildAddDiscountButton(), child: Column(
children: [
_buildAddDiscountButton(context),
const SizedBox(height: 5),
_todayState()
],
),
), ),
], ],
), ),
); );
} }
Widget _buildAddDiscountButton() { Widget _buildAddDiscountButton(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 16.0), padding: const EdgeInsets.only(top: 16.0),
child: SizedBox( child: SizedBox(
@ -105,10 +94,9 @@ class _HomePageState extends State<HomePage> {
), ),
), ),
onPressed: () { onPressed: () {
Navigator.of(context) Navigator.of(context).push(
.push(MaterialPageRoute(builder: (_) => const AddDiscountPage())) MaterialPageRoute(builder: (_) => const AddDiscountPage()),
.then((_) { ).then((_) {
// رفرش لیست بعد از بازگشت از صفحه افزودن
context.read<HomeBloc>().add(FetchDiscounts()); context.read<HomeBloc>().add(FetchDiscounts());
}); });
}, },
@ -132,245 +120,26 @@ class _HomePageState extends State<HomePage> {
); );
} }
Widget _buildDiscountCard(DiscountEntity discount) { Widget _todayState() {
final remaining = discount.endDate != null return Padding(
? discount.endDate!.difference(DateTime.now()) padding: const EdgeInsets.only(top: 16.0),
: const Duration(seconds: -1); child: SizedBox(
width: double.infinity,
return Column( child: ElevatedButton(
crossAxisAlignment: CrossAxisAlignment.start, style: ElevatedButton.styleFrom(
children: [ backgroundColor: AppColors.active,
Row( padding: const EdgeInsets.symmetric(vertical: 14),
mainAxisAlignment: MainAxisAlignment.spaceBetween, shape: RoundedRectangleBorder(
children: [ borderRadius: BorderRadius.circular(40),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
"تخفیف ${discount.type}",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
InkWell(
onTap: () {
// TODO: Implement edit functionality
},
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
SvgPicture.asset(Assets.icons.edit, width: 20, color: AppColors.active),
const SizedBox(width: 5),
const Text("ویرایش", style: TextStyle(color: AppColors.active)),
],
),
),
),
],
),
const Divider(height: 1),
const SizedBox(height: 10),
Card(
color: Colors.white,
elevation: 0,
margin: const EdgeInsets.only(bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(color: Colors.grey.shade300, width: 1),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (discount.images.isNotEmpty && discount.images.first.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.network(
discount.images.first,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(Icons.image_not_supported, color: Colors.grey),
),
),
)
else
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(Icons.store, color: Colors.grey, size: 50),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
SvgPicture.asset(Assets.icons.shop, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.shopName,
style: const TextStyle(fontSize: 16),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
SvgPicture.asset(Assets.icons.shoppingCart, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.name,
style: TextStyle(fontSize: 15, color: Colors.grey.shade600),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 12),
if (discount.endDate == null)
const Text(
'تاریخ نامعتبر',
style: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
)
else if (remaining.isNegative)
const Text(
'منقضی شده',
style: TextStyle(color: AppColors.expiryReserve, fontWeight: FontWeight.bold),
)
else
Row(
children: [
SvgPicture.asset(Assets.icons.timerPause, width: 18, color: Colors.grey.shade700),
const SizedBox(width: 10),
Expanded(child: _buildCountdownTimer(remaining)),
],
),
],
),
),
],
), ),
), ),
), onPressed: () {},
], child: const Text(
); "خلاصه عملکرد امروز",
} style: TextStyle(
fontSize: 18,
Widget _buildCountdownTimer(Duration remaining) { fontWeight: FontWeight.normal,
return Column( color: Colors.white,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Localizations.override(
context: context,
locale: const Locale('en'),
child: SlideCountdown(
duration: remaining,
slideDirection: SlideDirection.up,
separator: ':',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: AppColors.countdown,
),
separatorStyle: const TextStyle(
fontSize: 15,
color: AppColors.countdown,
),
decoration: const BoxDecoration(color: Colors.transparent),
shouldShowDays: (d) => d.inDays > 0,
shouldShowHours: (d) => true,
shouldShowMinutes: (d) => true,
),
),
const SizedBox(height: 4),
_buildTimerLabels(remaining),
],
);
}
Widget _buildTimerLabels(Duration duration) {
const labelStyle = TextStyle(fontSize: 10, color: AppColors.selectedImg);
List<Widget> labels = [];
if (duration.inDays > 0) {
labels.add(const SizedBox(width: 30, child: Text("روز", style: labelStyle)));
}
if (duration.inHours > 0 || duration.inDays > 0) {
labels.add(const SizedBox(width: 35, child: Text("ساعت", style: labelStyle)));
}
labels.add(const SizedBox(width: 30, child: Text("دقیقه", style: labelStyle)));
labels.add(const SizedBox(width: 30, child: Text("ثانیه", style: labelStyle)));
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: labels.reversed.toList(),
);
}
PreferredSizeWidget _buildCustomAppBar(BuildContext context) {
return PreferredSize(
preferredSize: const Size.fromHeight(70.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(15),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(Assets.icons.logoWithName),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
),
],
), ),
), ),
), ),

View File

@ -17,7 +17,6 @@ class LoginPage extends StatefulWidget {
class _LoginPageState extends State<LoginPage> { class _LoginPageState extends State<LoginPage> {
final TextEditingController _phoneController = TextEditingController(); final TextEditingController _phoneController = TextEditingController();
Country _selectedCountry = Country.parse('IR'); Country _selectedCountry = Country.parse('IR');
bool _keepSignedIn = false;
@override @override
void dispose() { void dispose() {

View File

@ -13,8 +13,11 @@ import 'package:flutter_svg/svg.dart';
class OtpPage extends StatefulWidget { class OtpPage extends StatefulWidget {
final String phoneNumber; final String phoneNumber;
final String countryCode; final String countryCode;
const OtpPage( const OtpPage({
{super.key, required this.phoneNumber, required this.countryCode}); super.key,
required this.phoneNumber,
required this.countryCode,
});
@override @override
State<OtpPage> createState() => _OtpPageState(); State<OtpPage> createState() => _OtpPageState();
@ -141,7 +144,7 @@ class _OtpPageState extends State<OtpPage> {
) )
else else
const SizedBox(height: 32), const SizedBox(height: 32),
// *** CHANGE IS HERE *** // *** CHANGE IS HERE ***
BlocConsumer<AuthBloc, AuthState>( BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) { listener: (context, state) {
@ -151,26 +154,29 @@ class _OtpPageState extends State<OtpPage> {
_errorMessage = state.message; _errorMessage = state.message;
}); });
} }
if (state is ShopExists) { if (state is ShopExists) {
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushReplacement(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => BlocProvider( builder:
create: (context) => HomeBloc(), (_) => BlocProvider(
child: const HomePage(), // بلافاصله پس از ایجاد، رویداد دریافت تخفیفها را ارسال میکند
), create:
(context) =>
HomeBloc()..add(FetchDiscounts()),
child: const HomePage(),
),
), ),
(route) => false,
); );
} }
// If no shop, navigate to StoreInfoPage to create one
if (state is NoShop) { if (state is NoShop) {
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => BlocProvider( builder:
create: (context) => StoreInfoBloc(), (_) => BlocProvider(
child: const StoreInfoPage(), create: (context) => StoreInfoBloc(),
), child: const StoreInfoPage(),
),
), ),
(route) => false, (route) => false,
); );
@ -206,19 +212,20 @@ class _OtpPageState extends State<OtpPage> {
builder: (context, canResend, child) { builder: (context, canResend, child) {
return canResend return canResend
? TextButton( ? TextButton(
onPressed: _resendOtp, onPressed: _resendOtp,
child: const Text( child: const Text(
"ارسال مجدد کد", "ارسال مجدد کد",
style: TextStyle(color: AppColors.active), style: TextStyle(color: AppColors.active),
), ),
) )
: ValueListenableBuilder<int>( : ValueListenableBuilder<int>(
valueListenable: _otpTimer.remainingSeconds, valueListenable: _otpTimer.remainingSeconds,
builder: (context, seconds, child) => Text( builder:
"${_otpTimer.formatTime()} تا دریافت مجدد", (context, seconds, child) => Text(
style: const TextStyle(color: Colors.grey), "${_otpTimer.formatTime()} تا دریافت مجدد",
), style: const TextStyle(color: Colors.grey),
); ),
);
}, },
), ),
], ],
@ -256,14 +263,15 @@ class _OtpPageState extends State<OtpPage> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: _hasError color:
? Colors.red _hasError
: (Theme.of(context) ? Colors.red
.inputDecorationTheme : (Theme.of(context)
.enabledBorder .inputDecorationTheme
?.borderSide .enabledBorder
.color ?? ?.borderSide
Colors.grey), .color ??
Colors.grey),
), ),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
@ -303,12 +311,12 @@ class _OtpPageState extends State<OtpPage> {
final otpCode = _controllers.map((c) => c.text).join(); final otpCode = _controllers.map((c) => c.text).join();
if (otpCode.length == 5) { if (otpCode.length == 5) {
context.read<AuthBloc>().add( context.read<AuthBloc>().add(
VerifyOTPEvent( VerifyOTPEvent(
otp: otpCode, otp: otpCode,
phoneNumber: widget.phoneNumber, phoneNumber: widget.phoneNumber,
countryCode: widget.countryCode, countryCode: widget.countryCode,
), ),
); );
} }
} }
@ -321,8 +329,12 @@ class _OtpPageState extends State<OtpPage> {
} }
_isOtpComplete = false; _isOtpComplete = false;
}); });
context.read<AuthBloc>().add(SendOTPEvent( context.read<AuthBloc>().add(
phoneNumber: widget.phoneNumber, countryCode: widget.countryCode)); SendOTPEvent(
phoneNumber: widget.phoneNumber,
countryCode: widget.countryCode,
),
);
_otpTimer.resetTimer(); _otpTimer.resetTimer();
} }
} }

View File

@ -1,6 +1,7 @@
import 'package:business_panel/core/config/app_colors.dart'; import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/gen/assets.gen.dart'; import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart'; import 'package:business_panel/presentation/pages/add_discount_page.dart';
import 'package:business_panel/presentation/widgets/custom_app_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -10,7 +11,7 @@ class ProductCreationLandingPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildCustomAppBar(context), appBar: CustomAppBar(),
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0), padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column( child: Column(
@ -59,56 +60,3 @@ class ProductCreationLandingPage extends StatelessWidget {
); );
} }
} }
PreferredSizeWidget _buildCustomAppBar(BuildContext context) {
return PreferredSize(
preferredSize: const Size.fromHeight(70.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
children: [
const SizedBox(height: 15),
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 8),
child: SvgPicture.asset(Assets.icons.logoWithName),
),
const Spacer(),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
),
],
),
],
),
),
),
),
);
}

View File

@ -33,38 +33,48 @@ class _SplashPageState extends State<SplashPage> {
MaterialPageRoute(builder: (_) => const OnboardingPage()), MaterialPageRoute(builder: (_) => const OnboardingPage()),
); );
} }
} else if (state is ShopExists) { } else if (state is ShopExists) {
// کاربر هم توکن دارد و هم فروشگاه، به HomePage میرود
Navigator.of(context).pushReplacement( Navigator.of(context).pushReplacement(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => BlocProvider( builder:
create: (context) => HomeBloc(), (_) => BlocProvider(
child: const HomePage(), // بلافاصله پس از ایجاد، رویداد دریافت تخفیفها را ارسال میکند
), create: (context) => HomeBloc()..add(FetchDiscounts()),
child: const HomePage(),
),
),
);
}
else if (state is AuthOffline) {
// کاربر توکن دارد ولی آفلاین است، به HomePage میرود
// HomePage خودش خطای شبکه را مدیریت خواهد کرد
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder:
(_) => BlocProvider(
create: (context) => HomeBloc(),
child: const HomePage(),
),
), ),
); );
} else if (state is NoShop) { } else if (state is NoShop) {
// کاربر توکن دارد ولی فروشگاه نساخته، به صفحه ساخت فروشگاه میرود // کاربر توکن دارد ولی فروشگاه نساخته، به صفحه ساخت فروشگاه میرود
Navigator.of(context).pushReplacement( Navigator.of(context).pushReplacement(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => BlocProvider( builder:
create: (context) => StoreInfoBloc(), (_) => BlocProvider(
child: const StoreInfoPage(), create: (context) => StoreInfoBloc(),
), child: const StoreInfoPage(),
),
), ),
); );
} else if (state is AuthFailure) { } else if (state is AuthFailure) {
// اگر در هر مرحله خطایی رخ داد، کاربر را به صفحه لاگین بفرست Navigator.of(context).pushReplacement(
Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const OnboardingPage()),
MaterialPageRoute(builder: (_) => const OnboardingPage()), );
);
} }
}, },
child: const Scaffold( child: const Scaffold(body: Center(child: CircularProgressIndicator())),
body: Center(
child: CircularProgressIndicator(),
),
),
); );
} }
} }

View File

@ -6,6 +6,7 @@ import 'package:business_panel/presentation/pages/store_info_display_page.dart';
import 'package:business_panel/presentation/pages/working_hours_dialog.dart'; import 'package:business_panel/presentation/pages/working_hours_dialog.dart';
import 'package:business_panel/presentation/store_info/bloc/store_info_bloc.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_bloc.dart';
import 'package:business_panel/presentation/store_info/bloc/store_info_state.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_state.dart';
import 'package:business_panel/presentation/widgets/custom_app_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -109,7 +110,7 @@ class _StoreInfoPageState extends State<StoreInfoPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildCustomAppBar(context), appBar: CustomAppBar(),
body: BlocListener<StoreInfoBloc, StoreInfoState>( body: BlocListener<StoreInfoBloc, StoreInfoState>(
listener: (context, state) { listener: (context, state) {
if (state.isSuccess) { if (state.isSuccess) {
@ -617,60 +618,6 @@ class _StoreInfoPageState extends State<StoreInfoPage> {
} }
} }
PreferredSizeWidget _buildCustomAppBar(BuildContext context) {
return PreferredSize(
preferredSize: const Size.fromHeight(70.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
children: [
const SizedBox(height: 15),
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 8),
child: SvgPicture.asset(Assets.icons.logoWithName),
),
const Spacer(),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
),
],
),
],
),
),
),
),
);
}

View File

@ -4,6 +4,7 @@ import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/pages/product_creation_landing_page.dart'; import 'package:business_panel/presentation/pages/product_creation_landing_page.dart';
import 'package:business_panel/presentation/store_info/bloc/store_info_bloc.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_bloc.dart';
import 'package:business_panel/presentation/store_info/bloc/store_info_state.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_state.dart';
import 'package:business_panel/presentation/widgets/custom_app_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
@ -16,7 +17,7 @@ class StoreInfoDisplayPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildCustomAppBar(context), appBar: CustomAppBar(),
body: BlocListener<StoreInfoBloc, StoreInfoState>( body: BlocListener<StoreInfoBloc, StoreInfoState>(
listener: (context, state) { listener: (context, state) {
if (state.isSuccess) { if (state.isSuccess) {
@ -198,62 +199,6 @@ class StoreInfoDisplayPage extends StatelessWidget {
); );
} }
PreferredSizeWidget _buildCustomAppBar(BuildContext context) {
return PreferredSize(
preferredSize: const Size.fromHeight(70.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(15),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
children: [
const SizedBox(height: 15),
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 8),
child: SvgPicture.asset(Assets.icons.logoWithName),
),
const Spacer(),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
],
),
],
),
],
),
),
),
),
);
}
String _translateDay(String day) { String _translateDay(String day) {
const Map<String, String> dayTranslations = { const Map<String, String> dayTranslations = {

View File

@ -0,0 +1,233 @@
import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/domain/entities/discount_entity.dart';
import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart' show NumberFormat;
import 'package:slide_countdown/slide_countdown.dart';
class ActiveDiscountCard extends StatelessWidget {
final DiscountEntity discount;
const ActiveDiscountCard({super.key, required this.discount});
@override
Widget build(BuildContext context) {
// ... (تمام کد مربوط به _buildDiscountCard از home_page.dart به اینجا منتقل شد)
// ... (متدهای کمکی مثل _buildCountdownTimer و _buildTimerLabels هم به اینجا منتقل شدند)
final remaining =
discount.endDate != null ? discount.endDate!.difference(DateTime.now()) : const Duration(seconds: -1);
final int discountPercentage = (discount.price > 0 && discount.price > discount.nPrice)
? (((discount.price - discount.nPrice) / discount.price) * 100).toInt()
: 0;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(8),
child: Text(
"تخفیف ${discount.type}",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
],
),
const Divider(height: 1),
const SizedBox(height: 10),
Card(
color: Colors.white,
elevation: 0,
margin: const EdgeInsets.only(bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(color: Colors.grey.shade300, width: 1),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (discount.images.isNotEmpty && discount.images.first.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.network(
discount.images.first,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(
Icons.image_not_supported,
color: Colors.grey,
),
),
),
)
else
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(
Icons.store,
color: Colors.grey,
size: 50,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
SvgPicture.asset(
Assets.icons.shoppingCart,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.name,
style: TextStyle(
fontSize: 15,
color: Colors.grey.shade600,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 12),
if (discount.endDate == null)
const Text(
'تاریخ نامعتبر',
style: TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
)
else if (remaining.isNegative)
const Text(
'منقضی شده',
style: TextStyle(
color: AppColors.expiryReserve,
fontWeight: FontWeight.bold,
),
)
else
Row(
children: [
SvgPicture.asset(
Assets.icons.timerPause,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(child: _buildCountdownTimer(remaining)),
],
),
const SizedBox(height: 16),
Row(
children: [
SvgPicture.asset(
Assets.icons.scanBarcode,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(
child: Text(
"اسکن بارکد مشتری",
style: TextStyle(
fontSize: 15,
color: AppColors.active,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
),
],
),
),
),
const SizedBox(height: 4),
],
);
}
Widget _buildCountdownTimer(Duration remaining) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: TextDirection.ltr,
child: SlideCountdown(
duration: remaining,
slideDirection: SlideDirection.up,
separator: ':',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: AppColors.countdown,
),
separatorStyle: const TextStyle(
fontSize: 15,
color: AppColors.countdown,
),
decoration: const BoxDecoration(color: Colors.transparent),
shouldShowDays: (d) => d.inDays > 0,
shouldShowHours: (d) => true,
shouldShowMinutes: (d) => true,
),
),
const SizedBox(height: 4),
_buildTimerLabels(remaining),
],
);
}
Widget _buildTimerLabels(Duration duration) {
const labelStyle = TextStyle(fontSize: 9, color: AppColors.selectedImg);
List<Widget> labels = [];
if (duration.inDays > 0) {
labels.add(const SizedBox(width: 30, child: Text("روز", style: labelStyle)));
}
if (duration.inHours > 0 || duration.inDays > 0) {
labels.add(const SizedBox(width: 35, child: Text("ساعت", style: labelStyle)));
}
labels.add(const SizedBox(width: 35, child: Text("دقیقه", style: labelStyle)));
labels.add(const SizedBox(width: 35, child: Text(" ثانیه", style: labelStyle)));
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: labels.reversed.toList(),
);
}
}

View File

@ -0,0 +1,111 @@
import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/discount_manegment_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
const CustomAppBar({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(Assets.icons.logoWithName),
Row(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
Assets.icons.discountShape,
color: Colors.black,
),
),
BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
final count =
state is HomeLoaded ? state.discounts.length : 0;
return Stack(
alignment: Alignment.center,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const DiscountManegment(),
),
);
},
icon: SvgPicture.asset(Assets.icons.scanBarcode),
),
if (count > 0)
Positioned(
top: 2,
right: 6,
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const DiscountManegment(),
),
);
},
child: Container(
padding: const EdgeInsets.all(4),
decoration: const BoxDecoration(
color: AppColors.selectedImg,
shape: BoxShape.circle,
),
constraints: const BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Text(
'$count',
style: const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
),
),
),
],
);
},
),
],
),
],
),
),
),
);
}
@override
Size get preferredSize => const Size.fromHeight(70.0);
}

View File

@ -0,0 +1,55 @@
import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/discount_manegment_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CustomAppBarSingle extends StatelessWidget implements PreferredSizeWidget {
String page = "";
CustomAppBarSingle({super.key,required this.page});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text("مدیریت $page",style: TextStyle(fontSize: 15)),
SizedBox(width: 15,),
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(Assets.icons.arrowLeft),
),
)
],
),
),
),
);
}
@override
Size get preferredSize => const Size.fromHeight(70.0);
}

View File

@ -0,0 +1,300 @@
import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/domain/entities/discount_entity.dart';
import 'package:business_panel/gen/assets.gen.dart';
import 'package:business_panel/presentation/home/bloc/home_bloc.dart';
import 'package:business_panel/presentation/pages/add_discount_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart' show NumberFormat;
import 'package:slide_countdown/slide_countdown.dart';
class DiscountCard extends StatelessWidget {
final DiscountEntity discount;
const DiscountCard({super.key, required this.discount});
@override
Widget build(BuildContext context) {
final remaining =
discount.endDate != null ? discount.endDate!.difference(DateTime.now()) : const Duration(seconds: -1);
final int discountPercentage = (discount.price > 0 && discount.price > discount.nPrice)
? (((discount.price - discount.nPrice) / discount.price) * 100).toInt()
: 0;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
"تخفیف ${discount.type}",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
InkWell(
onTap: () {
Navigator.of(context)
.push(
MaterialPageRoute(
builder: (_) => AddDiscountPage(discountId: discount.id),
),
)
.then((value) {
if (value == true) {
context.read<HomeBloc>().add(FetchDiscounts());
}
});
},
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
SvgPicture.asset(
Assets.icons.edit,
width: 20,
color: AppColors.active,
),
const SizedBox(width: 5),
const Text(
"ویرایش",
style: TextStyle(color: AppColors.active),
),
],
),
),
),
],
),
const Divider(height: 1),
const SizedBox(height: 10),
Card(
color: Colors.white,
elevation: 0,
margin: const EdgeInsets.only(bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(color: Colors.grey.shade300, width: 1),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (discount.images.isNotEmpty && discount.images.first.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.network(
discount.images.first,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(
Icons.image_not_supported,
color: Colors.grey,
),
),
),
)
else
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15),
),
child: const Icon(
Icons.store,
color: Colors.grey,
size: 50,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
SvgPicture.asset(
Assets.icons.shop,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.shopName,
style: const TextStyle(fontSize: 16),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
SvgPicture.asset(
Assets.icons.shoppingCart,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(
child: Text(
discount.name,
style: TextStyle(
fontSize: 15,
color: Colors.grey.shade600,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 12),
if (discount.endDate == null)
const Text(
'تاریخ نامعتبر',
style: TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
)
else if (remaining.isNegative)
const Text(
'منقضی شده',
style: TextStyle(
color: AppColors.expiryReserve,
fontWeight: FontWeight.bold,
),
)
else
Row(
children: [
SvgPicture.asset(
Assets.icons.timerPause,
width: 18,
color: Colors.grey.shade700,
),
const SizedBox(width: 10),
Expanded(child: _buildCountdownTimer(remaining)),
],
),
const SizedBox(height: 16),
],
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
NumberFormat('#,##0').format(discount.nPrice),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.red,
),
),
const SizedBox(width: 8),
if (discountPercentage > 0)
Text(
'($discountPercentage%)',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.red,
),
),
const SizedBox(width: 4),
Text(
NumberFormat('#,##0').format(discount.price),
style: const TextStyle(
fontSize: 14,
color: Color.fromARGB(255, 124, 124, 124),
decoration: TextDecoration.lineThrough,
),
),
const SizedBox(width: 4),
SvgPicture.asset(Assets.icons.cardPos),
],
),
),
const SizedBox(height: 4),
],
);
}
Widget _buildCountdownTimer(Duration remaining) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Directionality(
textDirection: TextDirection.ltr,
child: SlideCountdown(
duration: remaining,
slideDirection: SlideDirection.up,
separator: ':',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: AppColors.countdown,
),
separatorStyle: const TextStyle(
fontSize: 15,
color: AppColors.countdown,
),
decoration: const BoxDecoration(color: Colors.transparent),
shouldShowDays: (d) => d.inDays > 0,
shouldShowHours: (d) => true,
shouldShowMinutes: (d) => true,
),
),
const SizedBox(height: 4),
_buildTimerLabels(remaining),
],
);
}
Widget _buildTimerLabels(Duration duration) {
const labelStyle = TextStyle(fontSize: 9, color: AppColors.selectedImg);
List<Widget> labels = [];
if (duration.inDays > 0) {
labels.add(const SizedBox(width: 30, child: Text("روز", style: labelStyle)));
}
if (duration.inHours > 0 || duration.inDays > 0) {
labels.add(const SizedBox(width: 35, child: Text("ساعت", style: labelStyle)));
}
labels.add(const SizedBox(width: 35, child: Text("دقیقه", style: labelStyle)));
labels.add(const SizedBox(width: 35, child: Text(" ثانیه", style: labelStyle)));
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: labels.reversed.toList(),
);
}
}