feat: Implement the home screen with new UI components and assets, and refine authentication screens and routing.
22
assets/icons/agents_tab_icon.svg
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 20 22.7171" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 89">
|
||||||
|
<path id="Vector" d="M10.0023 11.8666C7.55016 11.8666 5.5239 8.92122 5.18678 4.86515C5.17969 4.80482 5.17969 4.73385 5.17969 4.66288C5.17969 2.09013 7.34434 0 10.0023 0C12.6602 0 14.8248 2.09013 14.8248 4.65933C14.8248 4.7303 14.8248 4.80127 14.8177 4.87225C14.4806 8.92121 12.4544 11.8666 10.0023 11.8666ZM10.0023 0.688431C7.72405 0.688431 5.86812 2.46984 5.86812 4.66288C5.86812 4.70901 5.86812 4.75514 5.87167 4.80127C6.1733 8.4386 7.95116 11.1781 10.0023 11.1781C12.0534 11.1781 13.8312 8.4386 14.1328 4.80837C14.1399 4.75514 14.1364 4.70901 14.1364 4.66288C14.1364 2.46984 12.2805 0.688431 10.0023 0.688431Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<path id="Vector_2" d="M12.4327 4.4082C11.7549 4.4082 11.1347 4.30631 10.5848 4.15261C9.03709 3.72003 7.22723 3.72773 5.70451 4.24142C5.52353 4.30174 5.32836 4.20593 5.26803 4.02495C5.2077 3.84397 5.30352 3.6488 5.4845 3.58847C6.07357 3.38975 7.16299 2.94972 7.85852 2.22935C7.98627 2.09451 8.20273 2.09096 8.33758 2.21516C8.36242 2.23645 10.8713 4.47918 14.2851 3.43943C14.466 3.38265 14.6577 3.48556 14.7144 3.67009C14.7712 3.85107 14.6683 4.0427 14.4838 4.09947C13.7563 4.31949 13.0679 4.4082 12.4327 4.4082Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<g id="Group">
|
||||||
|
<path id="Vector_3" d="M19.6558 22.713H0.344216C0.15259 22.713 0 22.5604 0 22.3688V18.0004C0 15.6583 1.1604 13.916 3.27182 13.0891C3.48829 13.004 3.69766 12.9224 3.90703 12.8443C4.4748 12.6278 4.95387 12.461 5.41164 12.3262L5.52519 12.2943C6.05394 12.1523 6.49042 11.9891 6.85238 11.8045C7.41661 11.5136 7.79986 11.1764 7.99148 10.7967C8.00923 10.7612 8.03052 10.7329 8.05891 10.7045C8.12278 10.6406 8.20795 10.6016 8.30376 10.6016C8.49539 10.6016 8.64798 10.7542 8.64798 10.9458C8.64798 11.0132 8.63023 11.0735 8.59475 11.1268C8.3357 11.6307 7.85309 12.0636 7.16466 12.4149C6.76011 12.6207 6.2775 12.8017 5.73101 12.9472L5.61036 12.9827C5.16324 13.114 4.70192 13.2737 4.14833 13.4866C3.93896 13.5647 3.73314 13.6463 3.52023 13.7279C1.17814 14.6434 0.684883 16.5561 0.684883 17.9969C0.684883 20.2193 2.48655 22.021 4.70901 22.021H15.2839C17.5044 22.021 19.3045 20.2209 19.3045 18.0004C19.3045 16.5597 18.8112 14.647 16.4727 13.7314C16.2598 13.6463 16.0539 13.5682 15.8481 13.4901C15.2945 13.2772 14.8332 13.1175 14.3896 12.9862L14.2761 12.9543C13.7189 12.8017 13.2363 12.6243 12.8318 12.4185C12.1363 12.0671 11.6501 11.6236 11.3911 11.109C11.3059 10.9387 11.3733 10.7329 11.5436 10.6477C11.714 10.5625 11.9198 10.63 12.005 10.8003C12.1966 11.1835 12.5798 11.5207 13.1441 11.8045C13.506 11.9891 13.9425 12.1523 14.4429 12.2872L14.5884 12.3297C15.0426 12.4646 15.5252 12.6278 16.093 12.8478C16.2988 12.9259 16.5117 13.0075 16.7282 13.0927C18.8361 13.916 20 15.6619 20 18.004V22.3723C20 22.5604 19.8439 22.713 19.6558 22.713Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<path id="Vector_4" d="M10.8973 14.8203H9.10528C8.94204 14.8203 8.8001 14.7032 8.76816 14.5435L8.49137 13.1808C8.47007 13.0815 8.49846 12.975 8.56234 12.8934C8.62621 12.8153 8.72557 12.7656 8.82848 12.7656H11.1706C11.2735 12.7656 11.3728 12.8118 11.4367 12.8934C11.5006 12.975 11.529 13.0779 11.5077 13.1808L11.2309 14.5435C11.2025 14.7067 11.0606 14.8203 10.8973 14.8203ZM9.33388 13.8625C9.36606 14.0193 9.50406 14.1318 9.66411 14.1318H10.3406C10.5013 14.1318 10.6397 14.0184 10.6712 13.8608C10.7129 13.6522 10.5534 13.4576 10.3406 13.4576H9.66411C9.45068 13.4576 9.29097 13.6534 9.33388 13.8625Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<path id="Vector_5" d="M8.87635 18.1394C8.86215 18.1394 8.84441 18.1394 8.83021 18.1358C8.64214 18.111 8.51084 17.9371 8.53568 17.749L8.98635 14.4382C9.01119 14.2501 9.18508 14.1188 9.37315 14.1436C9.56123 14.1685 9.69253 14.3424 9.66769 14.5304L9.21701 17.8413C9.19572 18.0152 9.04668 18.1394 8.87635 18.1394ZM11.1155 18.1429C10.9452 18.1429 10.7997 18.0187 10.7749 17.8448L10.3242 14.5304C10.2993 14.3424 10.4306 14.1685 10.6187 14.1436C10.8068 14.1188 10.9807 14.2501 11.0055 14.4382L11.4562 17.7526C11.481 17.9407 11.3497 18.1145 11.1617 18.1394C11.1475 18.1429 11.1297 18.1429 11.1155 18.1429ZM4.11765 22.7171C3.92603 22.7171 3.77344 22.5645 3.77344 22.3729V18.8562C3.77344 18.6646 3.92603 18.512 4.11765 18.512C4.30928 18.512 4.46187 18.6646 4.46187 18.8562V22.3729C4.46187 22.5645 4.30928 22.7171 4.11765 22.7171ZM15.8778 22.7171C15.6861 22.7171 15.5336 22.5645 15.5336 22.3729V18.8562C15.5336 18.6646 15.6861 18.512 15.8778 18.512C16.0694 18.512 16.222 18.6646 16.222 18.8562V22.3729C16.222 22.5645 16.0658 22.7171 15.8778 22.7171Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
<g id="Group_2">
|
||||||
|
<path id="Vector_6" d="M9.99733 20.87C9.85894 20.87 9.73119 20.7849 9.67796 20.6571L6.30677 12.4101C6.2358 12.2327 6.31742 12.034 6.49485 11.963C6.66873 11.8921 6.871 11.9772 6.94197 12.1511C8.06104 14.8857 11.9336 14.8857 13.0527 12.1511C13.1237 11.9737 13.3259 11.8921 13.4998 11.963C13.6772 12.034 13.7589 12.2363 13.6879 12.4101L10.3167 20.6571C10.2635 20.7849 10.1393 20.87 9.99733 20.87Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
<g id="Group_3">
|
||||||
|
<path id="Vector_7" d="M12.7036 10.3227C12.512 10.3227 12.3594 10.1701 12.3594 9.97846V7.13247C12.3594 7.04021 12.3984 6.95149 12.4623 6.88762L14.1656 5.23042C14.3005 5.09912 14.5205 5.09912 14.6518 5.23751C14.7831 5.37236 14.7831 5.59238 14.6447 5.72367C13.6214 6.71968 13.0443 8.087 13.0443 9.51495V9.98201C13.0478 10.1701 12.8952 10.3227 12.7036 10.3227Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<path id="Vector_8" d="M12.6988 8.60543C12.6775 8.60543 12.6562 8.60188 12.6314 8.59833L11.5739 8.39251C11.3858 8.35702 11.2652 8.17604 11.3042 7.98797C11.3432 7.79989 11.5207 7.67924 11.7088 7.71827L12.7662 7.92409C12.9543 7.95958 13.075 8.14056 13.0359 8.32863C13.004 8.49187 12.8621 8.60543 12.6988 8.60543ZM11.6449 9.64517C11.4852 9.64517 11.3397 9.53161 11.3078 9.36838C11.2723 9.1803 11.3929 9.00287 11.581 8.96384L12.6385 8.75802C12.8266 8.72253 13.004 8.84318 13.043 9.03126C13.0785 9.21934 12.9579 9.39677 12.7698 9.4358L11.7786 9.62872C11.7345 9.6373 11.6898 9.64517 11.6449 9.64517Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<g id="Group_4">
|
||||||
|
<path id="Vector_9" d="M7.30585 10.3214C7.11422 10.3214 6.96163 10.1688 6.96163 9.97715V9.50762C6.96163 8.08143 6.38431 6.71598 5.36121 5.72237C5.22636 5.59107 5.22281 5.37105 5.35411 5.23621C5.48541 5.10136 5.70542 5.09781 5.84027 5.22911L7.5436 6.88276C7.61103 6.94664 7.64651 7.03535 7.64651 7.13117V9.97715C7.65006 10.1688 7.49392 10.3214 7.30585 10.3214Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
<path id="Vector_10" d="M7.29998 8.6017C7.14029 8.6017 6.9948 8.48814 6.96286 8.32491C6.92737 8.13683 7.04803 7.9594 7.2361 7.92037L8.29359 7.71455C8.47812 7.67906 8.6591 7.79971 8.69813 7.98779C8.73362 8.17587 8.61297 8.3533 8.42489 8.39233L7.3674 8.59815C7.34611 8.6017 7.32482 8.6017 7.29998 8.6017ZM8.35747 9.64144C8.33617 9.64144 8.31488 9.6379 8.29004 9.63435L7.23255 9.42853C7.04448 9.39304 6.92382 9.21206 6.95931 9.02398C6.9948 8.83591 7.17578 8.71526 7.36385 8.75074L8.42134 8.95656C8.60942 8.99205 8.73007 9.17303 8.69458 9.3611C8.66265 9.52789 8.5207 9.64144 8.35747 9.64144ZM12.6974 7.47324C12.6568 7.47324 12.6169 7.46251 12.577 7.4553L11.2429 7.2147C10.4212 7.06651 9.57971 7.06651 8.75807 7.2147L7.36385 7.46614C7.17578 7.50163 6.99835 7.37388 6.96286 7.18935C6.92737 7.00127 7.05157 6.82384 7.23965 6.78836L9.9366 6.3022C9.97563 6.2951 10.0182 6.2951 10.0573 6.3022L12.7542 6.78836C12.9423 6.8203 13.0665 7.00127 13.031 7.18935C13.0062 7.35614 12.8642 7.47324 12.6974 7.47324Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.4 KiB |
3
assets/icons/hire_quickly_icon.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 42.3343 42.3343" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path id="Vector" d="M5.59967 0L5.41494 1.71831C5.3003 2.65651 4.8744 3.52919 4.20532 4.19684C3.53625 4.86449 2.66264 5.28854 1.72416 5.40122L0 5.57632V36.9253L1.67413 37.1485C3.64267 37.4064 5.1186 38.8072 5.42648 40.7179L5.69011 42.3343H37.081L37.2234 40.5678C37.3072 39.6856 37.6901 38.8585 38.3086 38.2236C38.927 37.5888 39.7438 37.1844 40.6236 37.0773L42.3343 36.8849V5.67446L40.7179 5.41469C38.8147 5.10682 37.3446 3.5867 37.1445 1.72023L36.9597 0H5.59967ZM8.8594 3.84839H33.7019C34.0903 4.97011 34.72 5.99303 35.5465 6.8451C36.373 7.69718 37.3763 8.35769 38.4857 8.78011V33.6504C37.3886 34.0553 36.3953 34.699 35.5776 35.535C34.7599 36.371 34.1383 37.3782 33.7577 38.4839H8.79398C8.36753 37.3771 7.70377 36.3772 6.84937 35.5544C5.99498 34.7316 4.9707 34.106 3.84857 33.7215V8.85131C5.00945 8.45367 6.06425 7.79632 6.93261 6.92934C7.80097 6.06235 8.45997 5.00861 8.8594 3.84839ZM10.1506 9.62098C9.77921 9.62098 9.42322 10.3656 10.0794 10.535C11.2975 10.8544 12.2077 11.3258 12.2077 13.048V20.8949C12.2077 27.3621 12.1903 29.8039 11.6169 30.8045C11.0069 31.6049 10.7625 31.6088 10.0044 31.8724C9.57331 31.8724 9.41745 32.7113 10.0044 32.7113C12.7041 32.7113 11.4014 32.5574 14.1031 32.5574C16.7624 32.5574 15.6618 32.7113 18.273 32.7113C18.7194 32.7113 18.6386 32.0764 18.273 31.9513C16.5796 31.3625 16.5739 31.1547 16.4449 30.9603C15.6733 29.7519 16.0062 24.4104 16.0062 22.084C16.0062 21.6722 16.4834 21.0911 17.0338 21.0911H25.3005C25.8508 21.0911 26.3281 21.6722 26.3281 22.084C26.3281 24.4104 26.661 29.75 25.8874 30.9603C25.7604 31.1624 25.7565 31.3644 24.0593 31.9513C23.6976 32.0764 23.6225 32.7113 24.0593 32.7113C26.6706 32.7113 25.5699 32.5574 28.2331 32.5574C30.9329 32.5574 29.6301 32.7113 32.3299 32.7113C32.911 32.7113 32.7609 31.8724 32.3299 31.8724C31.564 31.6088 31.3273 31.5972 30.7173 30.8064C30.1381 29.8058 30.1266 27.3621 30.1266 20.8968V13.0461C30.1266 11.3335 31.0349 10.8505 32.2549 10.5331C32.9168 10.3637 32.5435 9.61906 32.1779 9.61906C29.4646 9.61906 30.6481 9.773 27.9329 9.773C25.5025 9.773 26.7071 9.61906 24.2768 9.61906C24.0305 9.61906 23.6418 10.2637 24.1998 10.458C24.5654 10.5831 26.2569 10.7447 26.2569 13.5059C26.2569 17.0407 26.2684 17.7122 26.1799 18.7205C26.1799 18.8225 26.0067 19.7134 25.2254 19.7134H17.1088C16.3276 19.7134 16.1544 18.8206 16.1544 18.7205C16.0639 17.7142 16.0774 17.0407 16.0774 13.5059C16.0774 10.7447 17.7708 10.5812 18.1345 10.458C18.6925 10.2637 18.3057 9.61906 18.0575 9.61906C15.629 9.61906 16.8298 9.773 14.3975 9.773C11.6843 9.773 12.8658 9.61906 10.1506 9.61906V9.62098Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
5
assets/icons/lenders_tab_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="uit:calender">
|
||||||
|
<path id="Vector" d="M19.5 4H16.5V2.5C16.5 2.36739 16.4473 2.24021 16.3536 2.14645C16.2598 2.05268 16.1326 2 16 2C15.8674 2 15.7402 2.05268 15.6464 2.14645C15.5527 2.24021 15.5 2.36739 15.5 2.5V4H8.5V2.5C8.5 2.36739 8.44732 2.24021 8.35355 2.14645C8.25979 2.05268 8.13261 2 8 2C7.86739 2 7.74021 2.05268 7.64645 2.14645C7.55268 2.24021 7.5 2.36739 7.5 2.5V4H4.5C3.8372 4.00079 3.20178 4.26444 2.73311 4.73311C2.26444 5.20178 2.00079 5.8372 2 6.5V19.5C2.00079 20.1628 2.26444 20.7982 2.73311 21.2669C3.20178 21.7356 3.8372 21.9992 4.5 22H19.5C20.163 22 20.7989 21.7366 21.2678 21.2678C21.7366 20.7989 22 20.163 22 19.5V6.5C22 5.83696 21.7366 5.20107 21.2678 4.73223C20.7989 4.26339 20.163 4 19.5 4ZM21 19.5C21 19.8978 20.842 20.2794 20.5607 20.5607C20.2794 20.842 19.8978 21 19.5 21H4.5C4.10218 21 3.72064 20.842 3.43934 20.5607C3.15804 20.2794 3 19.8978 3 19.5V11H21V19.5ZM21 10H3V6.5C3 5.672 3.67 5 4.5 5H7.5V6.5C7.5 6.63261 7.55268 6.75979 7.64645 6.85355C7.74021 6.94732 7.86739 7 8 7C8.13261 7 8.25979 6.94732 8.35355 6.85355C8.44732 6.75979 8.5 6.63261 8.5 6.5V5H15.5V6.5C15.5 6.63261 15.5527 6.75979 15.6464 6.85355C15.7402 6.94732 15.8674 7 16 7C16.1326 7 16.2598 6.94732 16.3536 6.85355C16.4473 6.75979 16.5 6.63261 16.5 6.5V5H19.5C19.8978 5 20.2794 5.15804 20.5607 5.43934C20.842 5.72064 21 6.10218 21 6.5V10Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
5
assets/icons/location_filled_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18.6875 18.6875" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="tabler:location-filled">
|
||||||
|
<path id="Vector" d="M16.2632 1.55936L16.3458 1.55469L16.447 1.56092L16.5171 1.57337L16.6129 1.60063L16.6962 1.63645L16.774 1.68083L16.8441 1.733L16.908 1.7914L16.9485 1.83734L17.0123 1.92766L17.0528 2.00241C17.0891 2.08027 17.1125 2.16229 17.1229 2.24846L17.1268 2.331C17.1268 2.38965 17.1205 2.44676 17.1081 2.5023L17.0808 2.59807L11.9947 16.6736C11.8983 16.8835 11.7437 17.0614 11.5492 17.186C11.3547 17.3106 11.1286 17.3768 10.8976 17.3768C10.6896 17.3772 10.485 17.3239 10.3037 17.222C10.1224 17.12 9.97053 16.973 9.86278 16.7951L9.81217 16.6962L7.20215 11.4777L2.00858 8.88018C1.81641 8.79229 1.65069 8.65549 1.52798 8.48346C1.40527 8.31142 1.32989 8.11018 1.30936 7.89987L1.30469 7.78385C1.30469 7.34781 1.53906 6.94914 1.95953 6.71711L2.06854 6.6626L16.0974 1.59673L16.1799 1.57337L16.2632 1.55936Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
3
assets/icons/location_pin_icon.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 14.3648 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path id="Vector" d="M7.18241 9.5C6.50209 9.5 5.84964 9.23661 5.36858 8.76777C4.88752 8.29893 4.61726 7.66304 4.61726 7C4.61726 6.33696 4.88752 5.70107 5.36858 5.23223C5.84964 4.76339 6.50209 4.5 7.18241 4.5C7.86273 4.5 8.51518 4.76339 8.99624 5.23223C9.4773 5.70107 9.74756 6.33696 9.74756 7C9.74756 7.3283 9.68121 7.65339 9.5523 7.95671C9.42339 8.26002 9.23444 8.53562 8.99624 8.76777C8.75805 8.99991 8.47527 9.18406 8.16405 9.3097C7.85283 9.43534 7.51927 9.5 7.18241 9.5ZM7.18241 0C5.27752 0 3.45064 0.737498 2.10368 2.05025C0.756716 3.36301 0 5.14348 0 7C0 12.25 7.18241 20 7.18241 20C7.18241 20 14.3648 12.25 14.3648 7C14.3648 5.14348 13.6081 3.36301 12.2611 2.05025C10.9142 0.737498 9.0873 0 7.18241 0Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 924 B |
BIN
assets/icons/network_icon.svg
Normal file
|
After Width: | Height: | Size: 40 KiB |
7
assets/icons/notification_icon.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 35 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 25">
|
||||||
|
<line id="Line 5" y1="0.5" x2="35" y2="0.5" stroke="var(--stroke-0, #00293D)"/>
|
||||||
|
<line id="Line 6" y1="13.5" x2="35" y2="13.5" stroke="var(--stroke-0, #00293D)"/>
|
||||||
|
<line id="Line 7" y1="26.5" x2="35" y2="26.5" stroke="var(--stroke-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 444 B |
3
assets/icons/search_icon.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 11.6062 6.11302" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path id="Vector" d="M10.8006 0.137065L5.80257 5.00907L0.804566 0.137065C0.715272 0.0498356 0.595396 0.000999928 0.470566 0.000999928C0.345737 0.000999928 0.22586 0.0498356 0.136566 0.137065C0.0933286 0.17943 0.0589787 0.229995 0.0355287 0.285801C0.0120787 0.341608 0 0.401532 0 0.462065C0 0.522598 0.0120787 0.582522 0.0355287 0.638329C0.0589787 0.694135 0.0933286 0.744701 0.136566 0.787065L5.45357 5.97107C5.54694 6.06208 5.67217 6.11302 5.80257 6.11302C5.93296 6.11302 6.05819 6.06208 6.15157 5.97107L11.4686 0.788065C11.5121 0.745669 11.5467 0.694979 11.5704 0.638988C11.594 0.582997 11.6062 0.522839 11.6062 0.462065C11.6062 0.401291 11.594 0.341133 11.5704 0.285142C11.5467 0.229151 11.5121 0.178461 11.4686 0.136065C11.3793 0.0488352 11.2594 0 11.1346 0C11.0097 0 10.8899 0.0488352 10.8006 0.136065V0.137065Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
5
assets/icons/star_rating_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18.6875 18.6875" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="fills-2f2e233d-7bf4-8005-8007-35909656dd83">
|
||||||
|
<path id="Vector" d="M9.34375 0.0498047C9.76221 0.0498069 10.1188 0.299071 10.5225 0.826172C10.9261 1.35331 11.3673 2.1461 11.96 3.20898L12.2666 3.75781C12.6006 4.35723 12.7739 4.67105 13.0459 4.87793C13.3181 5.0851 13.6588 5.16086 14.3086 5.30762L14.9023 5.44238C16.0532 5.703 16.9105 5.89663 17.5146 6.13477C18.1177 6.37251 18.4557 6.64946 18.5859 7.06738C18.7158 7.48561 18.5979 7.9188 18.2432 8.48242C17.888 9.04652 17.3029 9.73017 16.5186 10.6475L16.1133 11.1211C15.6714 11.6382 15.4397 11.9078 15.3359 12.2412C15.2323 12.5755 15.268 12.935 15.335 13.625L15.3965 14.2578C15.5149 15.482 15.6033 16.3947 15.5732 17.0693C15.5432 17.7439 15.3944 18.1661 15.0547 18.4238C14.7158 18.6806 14.2879 18.6967 13.666 18.5186C13.0432 18.3401 12.2401 17.9716 11.1631 17.4756L10.6055 17.2188C9.99869 16.9386 9.68152 16.792 9.34375 16.792C9.00598 16.792 8.68881 16.9386 8.08203 17.2188L7.52539 17.4756C6.44781 17.9715 5.64431 18.34 5.02148 18.5186C4.3997 18.6968 3.9721 18.681 3.63379 18.4248C3.29358 18.1667 3.14542 17.744 3.11523 17.0693C3.08506 16.3946 3.17261 15.482 3.29102 14.2578L3.35254 13.626C3.41953 12.9351 3.45522 12.5756 3.35059 12.2422C3.24775 11.9078 3.01593 11.6381 2.57422 11.1221L2.16895 10.6475C1.38445 9.7305 0.799432 9.04656 0.444336 8.48242C0.0896948 7.91893 -0.0283174 7.48604 0.101562 7.06738C0.231389 6.64951 0.569463 6.37262 1.17285 6.13477C1.77735 5.89649 2.63514 5.70255 3.78613 5.44238L4.37988 5.30762C5.02881 5.16084 5.36851 5.08503 5.6416 4.87793C5.91437 4.67102 6.08697 4.35711 6.4209 3.75781L6.72754 3.20898C7.32025 2.1461 7.76135 1.35331 8.16504 0.826172C8.5687 0.299068 8.92529 0.0498047 9.34375 0.0498047Z" fill="var(--fill-0, #FFDE21)" stroke="var(--stroke-0, #00293D)" stroke-width="0.1"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
5
assets/icons/testimonial_bg.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 335.2 376.2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="fills-2f2e233d-7bf4-8005-8007-35914901e36e">
|
||||||
|
<path id="Vector" d="M317.375 0.0501953C327.19 0.0503211 335.15 7.63589 335.15 16.9984V359.202C335.15 368.564 327.19 376.15 317.375 376.15H17.8246C8.01037 376.15 0.0504548 368.564 0.0501953 359.202V16.9984C0.050444 7.63589 8.01037 0.050329 17.8246 0.0501953H317.375Z" stroke="var(--stroke-0, #00293D)" stroke-width="0.1"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 563 B |
5
assets/icons/top_rated_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 45 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="fills-2f2e233d-7bf4-8005-8007-35909656dd83">
|
||||||
|
<path id="Vector" d="M16.0944 7.1568C18.945 2.38572 20.3692 0 22.5 0C24.6308 0 26.055 2.38572 28.9056 7.1568L29.6438 8.39168C30.4537 9.74819 30.8582 10.4265 31.4887 10.8739C32.1185 11.3213 32.9057 11.487 34.481 11.8191L35.9123 12.1212C41.447 13.2911 44.2121 13.875 44.8713 15.8508C45.5282 17.825 43.6426 19.885 39.8695 24.0033L38.8932 25.068C37.8224 26.2376 37.2845 26.8235 37.0438 27.5458C36.8031 28.2706 36.8837 29.0516 37.046 30.612L37.1945 32.0337C37.764 37.5294 38.0495 40.2761 36.3259 41.4964C34.6022 42.7164 32.0108 41.6035 26.8313 39.3774L25.4877 38.802C24.0165 38.168 23.2808 37.8528 22.5 37.8528C21.7192 37.8528 20.9835 38.168 19.5123 38.802L18.1714 39.3774C12.9892 41.6035 10.3978 42.7163 8.6764 41.4984C6.95052 40.2761 7.23603 37.5294 7.80555 32.0337L7.95395 30.6141C8.1163 29.0516 8.1969 28.2706 7.95395 27.5481C7.71553 26.8235 7.17765 26.2376 6.10679 25.0699L5.13047 24.0033C1.35742 19.8871 -0.528162 17.8271 0.128742 15.8508C0.786022 13.875 3.55526 13.289 9.09035 12.1212L10.5213 11.8191C12.0943 11.487 12.8792 11.3213 13.5113 10.8739C14.1437 10.4265 14.5463 9.74819 15.3562 8.39168L16.0944 7.1568Z" fill="var(--fill-0, #FFDE21)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
5
assets/icons/trusted_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 38.77 40.6663" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="token:trust">
|
||||||
|
<path id="Vector" d="M7.82812 9.49146L21.553 5.08594V35.5857C11.749 31.519 7.82812 23.7247 7.82812 19.3192V9.49146ZM35.2779 9.49146L21.553 5.08594V35.5857C31.357 31.519 35.2779 23.7247 35.2779 19.3192V9.49146Z" fill="var(--fill-0, #638559)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 454 B |
5
assets/icons/verified_badge_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 19.5773 18.6875" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="fills-2f2e233d-7bf4-8005-8007-35909656dd81">
|
||||||
|
<path id="Vector" d="M14.4619 2.87305L14.4727 2.8916L14.4941 2.89648L17.6543 3.59863L17.3477 6.84766L17.3457 6.86914L17.3594 6.88477L19.5107 9.34375L17.3594 11.8027L17.3457 11.8184L17.3477 11.8398L17.6543 15.0879L14.4941 15.791L14.4727 15.7959L14.4619 15.8145L12.793 18.624L9.80859 17.3516L9.78906 17.3428L9.76953 17.3516L6.7832 18.624L5.11523 15.8145L5.10449 15.7959L5.08301 15.791L1.92285 15.0879L2.23047 11.8398L2.23242 11.8184L2.21777 11.8027L0.0664062 9.34375L2.21777 6.88477L2.23242 6.86914L2.23047 6.84766L1.92285 3.59863L5.08301 2.89648L5.10449 2.8916L5.11523 2.87305L6.7832 0.0625L9.76953 1.33594L9.78906 1.34473L9.80859 1.33594L12.793 0.0625L14.4619 2.87305ZM8.85449 9.89551L6.97559 8.0625L6.94043 8.02734L6.90527 8.0625L5.66016 9.30859L5.625 9.34375L8.85449 12.5732L8.88965 12.5381L13.918 7.51074L13.9521 7.47559L13.918 7.44043L12.6729 6.15039L12.6367 6.11328L8.85449 9.89551Z" fill="var(--fill-0, #1DA1F2)" stroke="var(--stroke-0, #00293D)" stroke-width="0.1"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
5
assets/icons/verified_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 45.2901 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="fills-2f2e233d-7bf4-8005-8007-35909656dd81">
|
||||||
|
<path id="Vector" d="M15.6456 42L11.7346 35.6001L4.32316 33.9999L5.0438 26.6001L0 21L5.0438 15.3999L4.32316 8.00006L11.7346 6.39994L15.6456 0L22.6452 2.89989L29.6449 0L33.5559 6.39994L40.9673 8.00006L40.2467 15.3999L45.2901 21L40.2467 26.6001L40.9673 33.9999L33.5559 35.6001L29.6449 42L22.6452 39.1001L15.6456 42ZM20.4837 28.1001L32.1149 16.8L29.233 13.8999L20.4837 22.3999L16.0575 18.1999L13.1756 21L20.4837 28.1001Z" fill="var(--fill-0, #1DA1F2)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 690 B |
BIN
assets/images/agent_card_image.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
assets/images/agent_profile_image.png
Normal file
|
After Width: | Height: | Size: 453 KiB |
16
assets/images/footer_bg.png
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 430 83" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Group 151">
|
||||||
|
<path id="Rectangle 170" d="M20 0.0498047H410C421.018 0.0498098 429.95 8.98192 429.95 20V82.9502H0.0498047V20C0.0498056 8.98192 8.98192 0.0498047 20 0.0498047Z" stroke="var(--stroke-0, #00293D)" stroke-width="0.1"/>
|
||||||
|
<g id="material-symbols:home">
|
||||||
|
<path id="Vector" d="M33 53.25V38.25L43 30.75L53 38.25V53.25H45.5V44.5H40.5V53.25H33Z" fill="var(--fill-0, #00293D)"/>
|
||||||
|
</g>
|
||||||
|
<line id="Line 28" x1="144.5" y1="80.5" x2="284.504" y2="80.5" stroke="var(--stroke-0, black)" stroke-linecap="round"/>
|
||||||
|
<g id="ic:baseline-message">
|
||||||
|
<path id="Vector_2" d="M274 33.5H254C252.625 33.5 251.512 34.625 251.512 36L251.5 58.5L256.5 53.5H274C275.375 53.5 276.5 52.375 276.5 51V36C276.5 34.625 275.375 33.5 274 33.5ZM271.5 48.5H256.5V46H271.5V48.5ZM271.5 44.75H256.5V42.25H271.5V44.75ZM271.5 41H256.5V38.5H271.5V41Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</g>
|
||||||
|
<g id="material-symbols:list">
|
||||||
|
<path id="Vector_3" d="M137.75 38.25V35.75H155.25V38.25H137.75ZM137.75 43.25V40.75H155.25V43.25H137.75ZM137.75 48.25V45.75H155.25V48.25H137.75ZM134 38.25C133.646 38.25 133.349 38.13 133.11 37.89C132.871 37.65 132.751 37.3533 132.75 37C132.749 36.6467 132.869 36.35 133.11 36.11C133.351 35.87 133.648 35.75 134 35.75C134.353 35.75 134.65 35.87 134.891 36.11C135.133 36.35 135.253 36.6467 135.25 37C135.248 37.3533 135.128 37.6504 134.89 37.8913C134.653 38.1321 134.356 38.2517 134 38.25ZM134 43.25C133.646 43.25 133.349 43.13 133.11 42.89C132.871 42.65 132.751 42.3533 132.75 42C132.749 41.6467 132.869 41.35 133.11 41.11C133.351 40.87 133.648 40.75 134 40.75C134.353 40.75 134.65 40.87 134.891 41.11C135.133 41.35 135.253 41.6467 135.25 42C135.248 42.3533 135.128 42.6504 134.89 42.8913C134.653 43.1321 134.356 43.2517 134 43.25ZM134 48.25C133.646 48.25 133.349 48.13 133.11 47.89C132.871 47.65 132.751 47.3533 132.75 47C132.749 46.6467 132.869 46.35 133.11 46.11C133.351 45.87 133.648 45.75 134 45.75C134.353 45.75 134.65 45.87 134.891 46.11C135.133 46.35 135.253 46.6467 135.25 47C135.248 47.3533 135.128 47.6504 134.89 47.8912C134.653 48.1321 134.356 48.2517 134 48.25Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</g>
|
||||||
|
<path id="Vector_4" fill-rule="evenodd" clip-rule="evenodd" d="M386 58.1875C388.14 58.1906 390.242 57.6279 392.094 56.5562V52.5625C392.094 51.4436 391.649 50.3706 390.858 49.5794C390.067 48.7882 388.994 48.3438 387.875 48.3438H384.125C383.006 48.3438 381.933 48.7882 381.142 49.5794C380.351 50.3706 379.906 51.4436 379.906 52.5625V56.5562C381.758 57.6279 383.86 58.1906 386 58.1875ZM394.906 52.5625V54.3194C396.528 52.5837 397.606 50.4121 398.01 48.0716C398.414 45.731 398.125 43.3235 397.179 41.1449C396.233 38.9664 394.671 37.1118 392.685 35.8091C390.698 34.5064 388.375 33.8124 386 33.8124C383.625 33.8124 381.302 34.5064 379.315 35.8091C377.329 37.1118 375.767 38.9664 374.821 41.1449C373.875 43.3235 373.586 45.731 373.99 48.0716C374.394 50.4121 375.472 52.5837 377.094 54.3194V52.5625C377.093 51.1128 377.541 49.6983 378.375 48.5128C379.21 47.3273 380.39 46.4287 381.755 45.94C381.047 45.1256 380.588 44.1248 380.433 43.0568C380.278 41.9889 380.434 40.8989 380.881 39.9169C381.329 38.9349 382.049 38.1024 382.957 37.5186C383.865 36.9348 384.921 36.6244 386 36.6244C387.079 36.6244 388.135 36.9348 389.043 37.5186C389.951 38.1024 390.671 38.9349 391.119 39.9169C391.566 40.8989 391.722 41.9889 391.567 43.0568C391.412 44.1248 390.953 45.1256 390.245 45.94C391.61 46.4287 392.79 47.3273 393.625 48.5128C394.459 49.6983 394.907 51.1128 394.906 52.5625ZM386 61C389.978 61 393.794 59.4196 396.607 56.6066C399.42 53.7936 401 49.9782 401 46C401 42.0218 399.42 38.2064 396.607 35.3934C393.794 32.5804 389.978 31 386 31C382.022 31 378.206 32.5804 375.393 35.3934C372.58 38.2064 371 42.0218 371 46C371 49.9782 372.58 53.7936 375.393 56.6066C378.206 59.4196 382.022 61 386 61ZM388.812 42.25C388.812 42.9959 388.516 43.7113 387.989 44.2387C387.461 44.7662 386.746 45.0625 386 45.0625C385.254 45.0625 384.539 44.7662 384.011 44.2387C383.484 43.7113 383.188 42.9959 383.188 42.25C383.188 41.5041 383.484 40.7887 384.011 40.2613C384.539 39.7338 385.254 39.4375 386 39.4375C386.746 39.4375 387.461 39.7338 387.989 40.2613C388.516 40.7887 388.812 41.5041 388.812 42.25Z" fill="var(--fill-0, #E58625)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/images/hero_bg.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
@@ -52,6 +52,32 @@ class AuthRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<UserModel> getMe() async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.get(ApiConstants.authMe);
|
||||||
|
final data = response.data['data'] as Map<String, dynamic>;
|
||||||
|
return UserModel.fromJson(data);
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.error is ApiException) {
|
||||||
|
throw e.error as ApiException;
|
||||||
|
}
|
||||||
|
throw ApiException(
|
||||||
|
message: e.message ?? 'Failed to fetch user',
|
||||||
|
statusCode: e.response?.statusCode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
try {
|
||||||
|
await _dio.post(ApiConstants.authLogout);
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore logout API errors — still clear local tokens
|
||||||
|
} finally {
|
||||||
|
await SecureStorage.clearTokens();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<UserModel> register(RegisterRequest request) async {
|
Future<UserModel> register(RegisterRequest request) async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.post(
|
final response = await _dio.post(
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
||||||
|
import 'package:real_estate_mobile/core/storage/secure_storage.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/data/auth_repository.dart';
|
import 'package:real_estate_mobile/features/auth/data/auth_repository.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
|
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';
|
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';
|
||||||
|
|
||||||
// Auth state
|
// Auth state
|
||||||
enum AuthStatus { initial, loading, success, error }
|
enum AuthStatus { initial, loading, authenticated, error }
|
||||||
|
|
||||||
class AuthState {
|
class AuthState {
|
||||||
final AuthStatus status;
|
final AuthStatus status;
|
||||||
@@ -49,7 +50,37 @@ class AuthState {
|
|||||||
class AuthNotifier extends StateNotifier<AuthState> {
|
class AuthNotifier extends StateNotifier<AuthState> {
|
||||||
final AuthRepository _repository;
|
final AuthRepository _repository;
|
||||||
|
|
||||||
AuthNotifier(this._repository) : super(const AuthState());
|
AuthNotifier(this._repository) : super(const AuthState()) {
|
||||||
|
checkAuthStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> checkAuthStatus() async {
|
||||||
|
final token = await SecureStorage.getAccessToken();
|
||||||
|
if (token == null) {
|
||||||
|
state = state.copyWith(status: AuthStatus.initial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = state.copyWith(status: AuthStatus.loading);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final user = await _repository.getMe();
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.authenticated,
|
||||||
|
user: user,
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
// Token is invalid/expired — clear and show login
|
||||||
|
await SecureStorage.clearTokens();
|
||||||
|
state = state.copyWith(status: AuthStatus.initial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
state = state.copyWith(status: AuthStatus.loading);
|
||||||
|
await _repository.logout();
|
||||||
|
state = const AuthState();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> login({
|
Future<void> login({
|
||||||
required String email,
|
required String email,
|
||||||
@@ -76,7 +107,7 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
status: AuthStatus.success,
|
status: AuthStatus.authenticated,
|
||||||
user: result['user'] as UserModel,
|
user: result['user'] as UserModel,
|
||||||
);
|
);
|
||||||
} on ApiException catch (e) {
|
} on ApiException catch (e) {
|
||||||
@@ -124,7 +155,7 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
status: AuthStatus.success,
|
status: AuthStatus.authenticated,
|
||||||
user: user,
|
user: user,
|
||||||
registeredEmail: email,
|
registeredEmail: email,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ class LoginScreen extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _LoginScreenState extends ConsumerState<LoginScreen> {
|
class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||||
final _nameController = TextEditingController();
|
|
||||||
final _emailController = TextEditingController();
|
final _emailController = TextEditingController();
|
||||||
final _passwordController = TextEditingController();
|
final _passwordController = TextEditingController();
|
||||||
String _selectedRole = 'USER';
|
String _selectedRole = 'USER';
|
||||||
@@ -24,7 +23,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_nameController.dispose();
|
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
_passwordController.dispose();
|
_passwordController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@@ -63,6 +61,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
|||||||
final authState = ref.watch(authProvider);
|
final authState = ref.watch(authProvider);
|
||||||
final isLoading = authState.status == AuthStatus.loading;
|
final isLoading = authState.status == AuthStatus.loading;
|
||||||
|
|
||||||
|
// Router redirect handles navigation on auth state change
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
body: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@@ -149,14 +149,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Name field
|
|
||||||
AuthTextField(
|
|
||||||
hintText: 'Name',
|
|
||||||
controller: _nameController,
|
|
||||||
keyboardType: TextInputType.name,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
|
|
||||||
// Email field
|
// Email field
|
||||||
AuthTextField(
|
AuthTextField(
|
||||||
hintText: 'Email',
|
hintText: 'Email',
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
|
|||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: authState.status == AuthStatus.success
|
child: authState.status == AuthStatus.authenticated
|
||||||
? _buildSuccessContent(authState)
|
? _buildSuccessContent(authState)
|
||||||
: _buildFormContent(authState),
|
: _buildFormContent(authState),
|
||||||
),
|
),
|
||||||
|
|||||||
118
lib/features/home/presentation/screens/home_screen.dart
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/features_section.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/hero_section.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/home_header.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/testimonials_section.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/top_professionals_section.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/widgets/trust_stats_section.dart';
|
||||||
|
|
||||||
|
class HomeScreen extends StatelessWidget {
|
||||||
|
const HomeScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Header
|
||||||
|
SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: const HomeHeader(),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Hero Section with Search
|
||||||
|
const HeroSection(),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
|
// Features Section
|
||||||
|
const FeaturesSection(),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
|
// Top Professionals Section
|
||||||
|
const TopProfessionalsSection(),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
|
// Trust & Stats Section
|
||||||
|
const TrustStatsSection(),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
|
// Testimonials Section
|
||||||
|
const TestimonialsSection(),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
_buildFooter(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFooter() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/icons/logo.png',
|
||||||
|
width: 109,
|
||||||
|
height: 29,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildFooterLink('Home'),
|
||||||
|
_buildFooterDot(),
|
||||||
|
_buildFooterLink('About'),
|
||||||
|
_buildFooterDot(),
|
||||||
|
_buildFooterLink('Contact'),
|
||||||
|
_buildFooterDot(),
|
||||||
|
_buildFooterLink('FAQ'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'\u00A9 2025 RE-QuestN. All rights reserved.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.white.withValues(alpha: 0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFooterLink(String text) {
|
||||||
|
return Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFooterDot() {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
child: Text(
|
||||||
|
'\u2022',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.white.withValues(alpha: 0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
129
lib/features/home/presentation/widgets/features_section.dart
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
|
||||||
|
class FeaturesSection extends StatelessWidget {
|
||||||
|
const FeaturesSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Find Trusted Real Estate Professionals On Demand',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 25,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'Quickly connect with the right agents exactly when you need them.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildFeatureCard(
|
||||||
|
icon: 'assets/icons/hire_quickly_icon.svg',
|
||||||
|
fallbackIcon: Icons.bolt,
|
||||||
|
title: 'Hire Quickly',
|
||||||
|
description:
|
||||||
|
'Connect with experienced local real estate agents who match your needs and preferences. Our simple process helps you get started quickly and move forward without delays or unnecessary complexity.',
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildFeatureCard(
|
||||||
|
icon: 'assets/icons/verified_icon.svg',
|
||||||
|
fallbackIcon: Icons.verified_user_outlined,
|
||||||
|
title: 'Verified Agents',
|
||||||
|
description:
|
||||||
|
'All agents are carefully identity-verified and background-checked to ensure trust and safety. You can confidently work with professionals who meet quality and reliability standards.',
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildFeatureCard(
|
||||||
|
icon: 'assets/icons/top_rated_icon.svg',
|
||||||
|
fallbackIcon: Icons.star_outline,
|
||||||
|
title: 'Top Rated',
|
||||||
|
description:
|
||||||
|
'Work with highly rated agents known for strong expertise and positive client feedback. Their consistent performance helps you make informed and confident property decisions.',
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildFeatureCard(
|
||||||
|
icon: 'assets/icons/trusted_icon.svg',
|
||||||
|
fallbackIcon: Icons.people_outline,
|
||||||
|
title: 'Trusted by Thousands',
|
||||||
|
description:
|
||||||
|
'Thousands of buyers, sellers, and renters trust our platform to connect with reliable, verified agents. Our experienced professionals support every step of the property journey, helping users make confident decisions with clarity, trust, and ease.',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFeatureCard({
|
||||||
|
required String icon,
|
||||||
|
required IconData fallbackIcon,
|
||||||
|
required String title,
|
||||||
|
required String description,
|
||||||
|
}) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
width: 0.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
icon,
|
||||||
|
width: 35,
|
||||||
|
height: 35,
|
||||||
|
placeholderBuilder: (_) => Icon(
|
||||||
|
fallbackIcon,
|
||||||
|
size: 35,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
description,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
136
lib/features/home/presentation/widgets/hero_section.dart
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
|
||||||
|
class HeroSection extends StatelessWidget {
|
||||||
|
const HeroSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
// Background image
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/hero_bg.png',
|
||||||
|
width: double.infinity,
|
||||||
|
height: 580,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Content overlay
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
const Text(
|
||||||
|
'Discover verified, top-rated real estate professionals.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
height: 1.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
// Search Agents Card
|
||||||
|
_buildSearchCard(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSearchCard() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Center(
|
||||||
|
child: Text(
|
||||||
|
'Search Agents',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildSearchField('Types'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildSearchField('Name or Keyword'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildSearchField('Location'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildSearchField('Categories'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// See All Agents button
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppColors.primaryDark,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'See All Agents',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSearchField(String hint) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
hint,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (hint == 'Types' || hint == 'Categories')
|
||||||
|
const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
262
lib/features/home/presentation/widgets/home_header.dart
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||||
|
|
||||||
|
class HomeHeader extends StatelessWidget {
|
||||||
|
const HomeHeader({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 23, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF648188),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// Logo
|
||||||
|
Image.asset(
|
||||||
|
'assets/icons/logo.png',
|
||||||
|
width: 109,
|
||||||
|
height: 29,
|
||||||
|
),
|
||||||
|
// Right side: notification + hamburger menu
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
// Notification bell
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: const Icon(
|
||||||
|
Icons.notifications_outlined,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
// Hamburger menu
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => _openDrawer(context),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.menu,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openDrawer(BuildContext context) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (context) => const _MenuDrawer(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MenuDrawer extends ConsumerWidget {
|
||||||
|
const _MenuDrawer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return DraggableScrollableSheet(
|
||||||
|
initialChildSize: 0.85,
|
||||||
|
minChildSize: 0.5,
|
||||||
|
maxChildSize: 0.95,
|
||||||
|
builder: (context, scrollController) {
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Handle bar
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.divider,
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
// Header with logo and close
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/icons/logo.png',
|
||||||
|
width: 109,
|
||||||
|
height: 29,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
child: Container(
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.inputFill,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.close,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
const Divider(color: AppColors.divider, height: 1),
|
||||||
|
// Menu items
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
controller: scrollController,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||||
|
children: [
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.home_outlined,
|
||||||
|
label: 'Home',
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
context.go('/home');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.school_outlined,
|
||||||
|
label: 'Education',
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.info_outline,
|
||||||
|
label: 'About Us',
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.help_outline,
|
||||||
|
label: "FAQ's",
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.mail_outline,
|
||||||
|
label: 'Contact',
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Divider(color: AppColors.divider, height: 1),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.person_outline,
|
||||||
|
label: 'Account Settings',
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
_buildMenuItem(
|
||||||
|
context,
|
||||||
|
icon: Icons.notifications_outlined,
|
||||||
|
label: 'Notification Settings',
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Divider(color: AppColors.divider, height: 1),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Log Out button
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
ref.read(authProvider.notifier).logout();
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.logout,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
label: const Text(
|
||||||
|
'Log Out',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMenuItem(
|
||||||
|
BuildContext context, {
|
||||||
|
required IconData icon,
|
||||||
|
required String label,
|
||||||
|
required VoidCallback onTap,
|
||||||
|
}) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: AppColors.primaryDark, size: 24),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
const Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
color: AppColors.hintText,
|
||||||
|
size: 22,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
111
lib/features/home/presentation/widgets/testimonials_section.dart
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
|
||||||
|
class TestimonialsSection extends StatelessWidget {
|
||||||
|
const TestimonialsSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
// Testimonial card
|
||||||
|
SizedBox(
|
||||||
|
height: 380,
|
||||||
|
child: ListView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
itemCount: 3,
|
||||||
|
itemBuilder: (context, index) => Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 16),
|
||||||
|
child: _buildTestimonialCard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTestimonialCard() {
|
||||||
|
return Container(
|
||||||
|
width: 315,
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Quote icon
|
||||||
|
const Text(
|
||||||
|
'\u201C',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 48,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
height: 0.8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'I have been working with Lorem ..',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Sed dignissim, nisl eget tincidunt vulputate, lacus justo bibendum ipsum, vitae tempus risus lorem at nunc.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
// Stars
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
5,
|
||||||
|
(index) => const Padding(
|
||||||
|
padding: EdgeInsets.only(right: 4),
|
||||||
|
child: Icon(
|
||||||
|
Icons.star,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// Author info
|
||||||
|
const Text(
|
||||||
|
'Conor Kenney',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Chief Operations Officer',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
|
||||||
|
class TopProfessionalsSection extends StatelessWidget {
|
||||||
|
const TopProfessionalsSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'"Meet top real estate professionals"',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 25,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
// Agents / Lenders Tab
|
||||||
|
_buildCategoryTab(),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
// Agent Card
|
||||||
|
_buildAgentCard(),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Progress indicator
|
||||||
|
_buildProgressIndicator(),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
|
||||||
|
// See All Agents CTA
|
||||||
|
_buildSeeAllAgentsCta(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCategoryTab() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Active tab - Agents
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/agents_tab_icon.svg',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.people,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
const Text(
|
||||||
|
'Agents',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Inactive tab - Lenders
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/lenders_tab_icon.svg',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.calendar_today,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
const Text(
|
||||||
|
'Lenders',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAgentCard() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Agent image
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(15)),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/agent_profile_image.png',
|
||||||
|
width: double.infinity,
|
||||||
|
height: 192,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 192,
|
||||||
|
color: AppColors.gradientStart,
|
||||||
|
child: const Icon(Icons.person, size: 60, color: AppColors.primaryDark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Name and badges row
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Arjun Mehta',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/verified_badge_icon.svg',
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.verified,
|
||||||
|
color: Colors.blue,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/star_rating_icon.svg',
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.star,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
const Text(
|
||||||
|
'4.9 Rating',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
// Verified and Location
|
||||||
|
const Text(
|
||||||
|
'"Verified local agent"',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Color(0xFF638559),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// Location
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Location:',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/location_pin_icon.svg',
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
const Text(
|
||||||
|
'San Francisco, CA',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// Expertise
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Expertise:',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
const Text(
|
||||||
|
'(Residential Property Expert)',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// Tags
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
_buildTag('Residential'),
|
||||||
|
_buildTag('Rental'),
|
||||||
|
_buildTag('Commercial'),
|
||||||
|
_buildTag('Inspection'),
|
||||||
|
_buildTag('Land'),
|
||||||
|
_buildTag('Rental'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// Experience
|
||||||
|
RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: 'Experience: ',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: '10+ years in the real estate industry.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTag(String label) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildProgressIndicator() {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 5,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 5,
|
||||||
|
width: 103,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSeeAllAgentsCta() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [AppColors.gradientStart, AppColors.gradientEnd],
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.primaryDark, width: 0.2),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color(0xFFD9D9D9),
|
||||||
|
offset: Offset(10, 0),
|
||||||
|
blurRadius: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/icons/network_icon.svg',
|
||||||
|
width: 30,
|
||||||
|
height: 23,
|
||||||
|
errorBuilder: (_, __, ___) => const Icon(
|
||||||
|
Icons.hub,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Text(
|
||||||
|
'Discover 5,000+ Top Real Estate Agents in Our Network',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppColors.primaryDark,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'See All Agents',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
140
lib/features/home/presentation/widgets/trust_stats_section.dart
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
|
||||||
|
class TrustStatsSection extends StatelessWidget {
|
||||||
|
const TrustStatsSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"Our Clients' Trust Is Our Foundation",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 25,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Text(
|
||||||
|
'We help buyers, sellers, and investors close successful real estate deals with confidence in every transaction.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Divider(color: AppColors.divider),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
// Stats row
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Cities stat
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: '25+ Cities &\n',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: 'neighborhoods served',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: '1,000+ Properties\n',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: 'bought and sold for our clients.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Rating visual
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'4.9',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 32,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
5,
|
||||||
|
(index) => Icon(
|
||||||
|
index < 4 ? Icons.star : Icons.star_half,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,15 +10,17 @@ Future<void> mainCommon(Flavor flavor) async {
|
|||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends ConsumerWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final router = ref.watch(routerProvider);
|
||||||
|
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
title: 'RE-QuestN',
|
title: 'RE-QuestN',
|
||||||
theme: AppTheme.light,
|
theme: AppTheme.light,
|
||||||
routerConfig: AppRouter.router,
|
routerConfig: router,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,64 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/presentation/screens/login_screen.dart';
|
import 'package:real_estate_mobile/features/auth/presentation/screens/login_screen.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/presentation/screens/signup_screen.dart';
|
import 'package:real_estate_mobile/features/auth/presentation/screens/signup_screen.dart';
|
||||||
|
import 'package:real_estate_mobile/features/home/presentation/screens/home_screen.dart';
|
||||||
|
|
||||||
class AppRouter {
|
final routerProvider = Provider<GoRouter>((ref) {
|
||||||
AppRouter._();
|
final authRefreshNotifier = _AuthRefreshNotifier();
|
||||||
|
|
||||||
static final GoRouter router = GoRouter(
|
ref.listen(authProvider, (_, __) {
|
||||||
initialLocation: '/signup',
|
authRefreshNotifier.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
authRefreshNotifier.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return GoRouter(
|
||||||
|
initialLocation: '/login',
|
||||||
|
refreshListenable: authRefreshNotifier,
|
||||||
|
redirect: (context, state) {
|
||||||
|
final authState = ref.read(authProvider);
|
||||||
|
final isAuthenticated = authState.status == AuthStatus.authenticated;
|
||||||
|
final isLoading = authState.status == AuthStatus.loading;
|
||||||
|
|
||||||
|
final isAuthRoute = state.matchedLocation == '/login' ||
|
||||||
|
state.matchedLocation == '/signup';
|
||||||
|
|
||||||
|
// While checking auth status, don't redirect
|
||||||
|
if (isLoading) return null;
|
||||||
|
|
||||||
|
// If authenticated and on auth page, go to home
|
||||||
|
if (isAuthenticated && isAuthRoute) return '/home';
|
||||||
|
|
||||||
|
// If not authenticated and on protected page, go to login
|
||||||
|
if (!isAuthenticated && !isAuthRoute) return '/login';
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
routes: [
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: '/login',
|
||||||
|
builder: (context, state) => const LoginScreen(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/signup',
|
path: '/signup',
|
||||||
builder: (context, state) => const SignupScreen(),
|
builder: (context, state) => const SignupScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/login',
|
path: '/home',
|
||||||
builder: (context, state) => const LoginScreen(),
|
builder: (context, state) => const HomeScreen(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Notifier that triggers GoRouter refresh when auth state changes.
|
||||||
|
class _AuthRefreshNotifier extends ChangeNotifier {
|
||||||
|
void notify() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||