From 54623fb720c545d11a8c648abde6c090f25a4922 Mon Sep 17 00:00:00 2001 From: payacom <59262811+payacom@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:39:10 +0330 Subject: [PATCH] verify --- public/images/icons/verify-blue.svg | 13 ++ public/images/icons/verify-gold.svg | 13 ++ public/images/icons/verify-gray.svg | 13 ++ public/images/icons/verify-green.svg | 13 ++ src/api/fetchStories.ts | 22 ++- src/api/trackExploreInteraction.ts | 10 +- src/app/(auth)/verify/confirm/page.tsx | 10 +- .../academy/[id]/[title]/CourseClient.tsx | 23 ++- .../[academyId]/AcademyProfileClient.tsx | 10 +- src/app/booking/[userId]/page.tsx | 20 +- src/app/gift/[userId]/page.tsx | 3 +- src/app/icon.png | Bin 11537 -> 31796 bytes src/app/new-post/page.tsx | 74 ++++++- src/app/offer/[id]/page.tsx | 3 +- src/app/settings/booking/new/name/page.tsx | 4 +- src/app/settings/booking/new/preview/page.tsx | 10 +- .../settings/booking/new/schedule/page.tsx | 36 +++- .../settings/booking/new/services/page.tsx | 99 ++++++++-- .../settings/booking/reservations/page.tsx | 4 +- src/app/settings/chats/nearby/page.tsx | 6 +- src/app/settings/chats/page.tsx | 6 +- .../settings/chats/rooms/[roomId]/page.tsx | 3 +- .../chats/shop/[shopId]/[buyerId]/page.tsx | 7 +- src/app/settings/edit/License/page.tsx | 2 + .../settings/profile/user-settings/page.tsx | 11 ++ .../[listingId]/ListingDetailClient.tsx | 20 ++ src/components/TabNavigation.tsx | 185 ++++++++---------- .../academy/CourseCommentsContent.tsx | 3 + src/components/academy/MainModelCard.tsx | 4 +- src/components/academy/ModelHead.tsx | 4 + src/components/auth/AuthUserDetails.tsx | 2 + .../billboards/BillboardDetailContent.tsx | 20 ++ .../BillboardCommentsModal.tsx | 5 +- src/components/chat/ChatHeader.tsx | 7 + src/components/chat/ChatHeaderMenu.tsx | 2 + src/components/chat/MessageInput.tsx | 12 +- src/components/elements/Modal.tsx | 9 +- src/components/explore/ExploreAuthor.tsx | 2 + src/components/explore/ExploreGrid.tsx | 39 +++- src/components/main/Header.tsx | 3 +- src/components/main/ProfileAvatar.tsx | 58 +++++- src/components/main/UserInfo.tsx | 22 ++- src/components/main/VerificationBadge.tsx | 117 +++++------ .../models/MainModelCard/MainModelCard.tsx | 7 +- .../models/ModelPage/MainModelCardPost.tsx | 4 +- src/components/models/ModelPage/ModelHead.tsx | 4 + .../models/ModelPage/ModelHeadRowTwo.tsx | 10 +- src/components/posts/PostCommentsContent.tsx | 3 + src/components/posts/PostLinkPicker.tsx | 52 +++++ src/components/posts/ReelsPostCard.tsx | 7 +- .../projects/ProjectPage/ProjectCreator.tsx | 4 +- .../projects/ProjectPage/ProjectRequests.tsx | 3 +- .../Workroom/ProjectRequestsAction.tsx | 6 +- .../Workroom/ProjectWorkroomSelectedUser.tsx | 3 +- src/components/search/SearchCard.tsx | 41 ++-- src/components/settings/UserDetails.tsx | 7 +- src/components/settings/gifts/GiftItem.tsx | 3 +- src/components/settings/offers/OffersItem.tsx | 3 +- src/components/shops/ShopReelsView.tsx | 42 ++++ src/components/stories/StoriesBar.tsx | 2 + src/components/stories/StoryEditor.tsx | 146 ++++++++++++-- src/components/stories/StoryLinkPicker.tsx | 179 +++++++++++++++++ src/components/stories/StoryRing.tsx | 68 +++++-- src/components/stories/StoryViewer.tsx | 112 ++++++++--- src/components/ui/alert-dialog.tsx | 3 + src/components/ui/dialog.tsx | 4 + src/components/ui/drawer.tsx | 3 + src/components/ui/sheet.tsx | 3 + src/lib/captionLength.ts | 11 +- src/lib/glassBackdrop.ts | 28 +++ src/lib/postLinkCaption.ts | 11 +- src/locales/en/common.json | 11 ++ src/locales/fa/common.json | 11 ++ src/types/types.ts | 7 + 74 files changed, 1361 insertions(+), 366 deletions(-) create mode 100644 public/images/icons/verify-blue.svg create mode 100644 public/images/icons/verify-gold.svg create mode 100644 public/images/icons/verify-gray.svg create mode 100644 public/images/icons/verify-green.svg create mode 100644 src/components/stories/StoryLinkPicker.tsx create mode 100644 src/lib/glassBackdrop.ts diff --git a/public/images/icons/verify-blue.svg b/public/images/icons/verify-blue.svg new file mode 100644 index 0000000..1f73680 --- /dev/null +++ b/public/images/icons/verify-blue.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/public/images/icons/verify-gold.svg b/public/images/icons/verify-gold.svg new file mode 100644 index 0000000..a17ad67 --- /dev/null +++ b/public/images/icons/verify-gold.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/public/images/icons/verify-gray.svg b/public/images/icons/verify-gray.svg new file mode 100644 index 0000000..c0f61f3 --- /dev/null +++ b/public/images/icons/verify-gray.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/public/images/icons/verify-green.svg b/public/images/icons/verify-green.svg new file mode 100644 index 0000000..e584428 --- /dev/null +++ b/public/images/icons/verify-green.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/src/api/fetchStories.ts b/src/api/fetchStories.ts index 4b72eaa..346eb93 100644 --- a/src/api/fetchStories.ts +++ b/src/api/fetchStories.ts @@ -1,6 +1,8 @@ import { getApiBaseUrl } from "@/components/main/BaseUrl"; +import type { PostLinkKind } from "@/lib/postLinkCaption"; export type StoryTextOverlay = { + type?: "text"; text: string; x: number; y: number; @@ -11,12 +13,25 @@ export type StoryTextOverlay = { align?: "left" | "center" | "right"; }; +/** اورلی لینک روی استوری — همون ۶ مورد قابل‌لینک ثبت پست (پکیج/پروژه/بیلبورد/فروشگاه/کالا/رزرو) */ +export type StoryLinkOverlay = { + type: "link"; + link_kind: PostLinkKind; + link_id: string; + link_title: string; + x: number; + y: number; + rotation?: number; +}; + +export type StoryOverlay = StoryTextOverlay | StoryLinkOverlay; + export type StoryItem = { _id: string; media_path: string; media_type: "image" | "video"; linked_post_id?: string | null; - overlays?: StoryTextOverlay[]; + overlays?: StoryOverlay[]; createdAt?: string; expires_at?: string; viewed?: boolean; @@ -31,6 +46,7 @@ export type StoryFeedUser = { first_name: string; last_name: string; profile_image?: string; + verify_badge?: string; }; stories: StoryItem[]; has_unviewed: boolean; @@ -73,7 +89,7 @@ export async function markStoryViewed( export async function createStoryBase64( file: { name: string; type: string; data: string }, token: string, - overlays: StoryTextOverlay[] = [] + overlays: StoryOverlay[] = [] ): Promise { const res = await fetch(`${getApiBaseUrl()}/stories/create-base64`, { method: "POST", @@ -91,7 +107,7 @@ export async function createStoryBase64( export async function updateStoryOverlays( storyId: string, - overlays: StoryTextOverlay[], + overlays: StoryOverlay[], token: string ): Promise { const res = await fetch(`${getApiBaseUrl()}/stories/${storyId}`, { diff --git a/src/api/trackExploreInteraction.ts b/src/api/trackExploreInteraction.ts index 7425539..cf13a53 100644 --- a/src/api/trackExploreInteraction.ts +++ b/src/api/trackExploreInteraction.ts @@ -1,10 +1,16 @@ import { getApiBaseUrl } from "@/components/main/BaseUrl"; export type ExploreInteractionPayload = { - targetType: "post" | "profile" | "academy"; + targetType: + | "post" + | "profile" + | "academy" + | "shop_product" + | "academy_course" + | "billboard"; targetId: string; authorId?: string; - contentType?: "image" | "video" | "academy"; + contentType?: "image" | "video" | "academy" | "shop_product" | "billboard"; action?: | "view" | "profile_visit" diff --git a/src/app/(auth)/verify/confirm/page.tsx b/src/app/(auth)/verify/confirm/page.tsx index 155444d..cc7dc66 100644 --- a/src/app/(auth)/verify/confirm/page.tsx +++ b/src/app/(auth)/verify/confirm/page.tsx @@ -27,14 +27,14 @@ function Confirm() { useEffect(() => { const markComplete = async () => { try { - const response = await request<{ is_verified?: string }>( + const response = await request<{ verify_badge?: string }>( "POST", "/verify/complete", {} ); - setVerifiedStatus(response?.is_verified ?? "none"); + setVerifiedStatus(response?.verify_badge ?? "none"); } catch { - setVerifiedStatus(user?.is_verified ?? "none"); + setVerifiedStatus(user?.verify_badge ?? "none"); } }; markComplete(); @@ -62,6 +62,8 @@ function Confirm() { alt={user?.user_name || "user profile"} size="xl" rounded="2xl" + userId={user?._id} + verifyBadge={verifiedStatus ?? user?.verify_badge} />
{formatFullName(user?.first_name, user?.last_name)} @@ -69,7 +71,7 @@ function Confirm() { {user?.user_name}
diff --git a/src/app/(projects)/academy/[id]/[title]/CourseClient.tsx b/src/app/(projects)/academy/[id]/[title]/CourseClient.tsx index f0ed792..332c603 100644 --- a/src/app/(projects)/academy/[id]/[title]/CourseClient.tsx +++ b/src/app/(projects)/academy/[id]/[title]/CourseClient.tsx @@ -28,6 +28,7 @@ import VerificationBadge from "@/components/main/VerificationBadge"; import ProfileAvatar from "@/components/main/ProfileAvatar"; import { usePathname } from "next/navigation"; import Cookies from "js-cookie"; +import { trackExploreInteraction } from "@/api/trackExploreInteraction"; import BillboardContactInfoModal from "@/components/billboards/BillboardPage/BillboardContactInfoModal"; import { AcademyCourseDetailSkeleton } from "@/components/academy/AcademySkeletons"; import { useTranslation } from "react-i18next"; @@ -372,6 +373,24 @@ export default function CourseDetail({ } }, [id, request]); + useEffect(() => { + const course = courses[0]; + if (!course?._id) return; + const token = Cookies.get("token") || ""; + if (!token) return; + trackExploreInteraction( + { + targetType: "academy_course", + targetId: course._id, + authorId: course.user_id || course.academyId, + contentType: "academy", + action: "view", + }, + token + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [courses[0]?._id]); + // خرید دوره // const handlePurchase = async () => { // setPurchasing(true); @@ -743,6 +762,8 @@ useEffect(() => { size="chat" rounded="full" fallback="/images/default-avatar.png" + userId={typeof item?.user_id === "object" ? item.user_id?._id : undefined} + verifyBadge={typeof item?.user_id === "object" ? item.user_id?.verify_badge : undefined} /> @@ -751,7 +772,7 @@ useEffect(() => {
{item?.user_id?.user_name || t("common.user")} - + {item?.rate > 0 && ( diff --git a/src/app/(projects)/academy/profile/[academyId]/AcademyProfileClient.tsx b/src/app/(projects)/academy/profile/[academyId]/AcademyProfileClient.tsx index e4aa898..c006a7a 100644 --- a/src/app/(projects)/academy/profile/[academyId]/AcademyProfileClient.tsx +++ b/src/app/(projects)/academy/profile/[academyId]/AcademyProfileClient.tsx @@ -33,6 +33,7 @@ interface AcademyOwner { first_name?: string; last_name?: string; is_verified?: string; + verify_badge?: string; is_Register?: string | boolean; user_score?: string | number; } @@ -199,7 +200,7 @@ export default function AcademyProfileClient() { const displayUserName = owner?.user_name || ownerFromApi?.user_name; const displayUserScore = owner?.user_score ?? ownerFromApi?.user_score ?? 0; - const isVerified = owner?.is_verified ?? ownerFromApi?.is_verified; + const isVerified = owner?.verify_badge ?? ownerFromApi?.verify_badge; const isRegister = owner?.is_Register ?? ownerFromApi?.is_Register; const stats = academy.stats; const shareUrl = `modstagram.com/academy/profile/${academyId}`; @@ -250,6 +251,8 @@ export default function AcademyProfileClient() { : undefined } alt={academyName} + userId={owner?._id ?? ownerFromApi?._id} + verifyBadge={isVerified} size="md" rounded="xl" className="md:h-[120px] md:w-[120px]" @@ -293,10 +296,7 @@ export default function AcademyProfileClient() { )} > {displayUserName} - + ) : null}
diff --git a/src/app/booking/[userId]/page.tsx b/src/app/booking/[userId]/page.tsx index 8a1a073..7cc768a 100644 --- a/src/app/booking/[userId]/page.tsx +++ b/src/app/booking/[userId]/page.tsx @@ -31,15 +31,21 @@ type TimeSlot = { start_time: string; end_time: string }; const DAY_KEYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]; -function buildUpcomingDates(config: BookingConfig, count = 21) { +function buildUpcomingDates( + config: BookingConfig, + repeatExpiresAt: string | null, + count = 21 +) { const openDays = new Set(config.weeklySchedule.map((entry) => entry.day)); const holidaySet = new Set(config.holidayDates.map((d) => d.slice(0, 10))); + const expiresAtTime = repeatExpiresAt ? new Date(repeatExpiresAt).getTime() : null; const dates: string[] = []; const cursor = new Date(); for (let i = 0; i < 60 && dates.length < count; i++) { const date = new Date(cursor); date.setDate(cursor.getDate() + i); + if (expiresAtTime !== null && date.getTime() >= expiresAtTime) break; const iso = date.toISOString().slice(0, 10); const dayKey = DAY_KEYS[date.getDay()]; if (openDays.has(dayKey) && !holidaySet.has(iso)) { @@ -56,6 +62,7 @@ function BookingFlowPage() { const params = useParams<{ userId: string }>(); const [config, setConfig] = useState(undefined); + const [repeatExpiresAt, setRepeatExpiresAt] = useState(null); const [step, setStep] = useState<"service" | "datetime" | "confirm">("service"); const [selectedService, setSelectedService] = useState(null); const [selectedDate, setSelectedDate] = useState(null); @@ -63,16 +70,19 @@ function BookingFlowPage() { const [selectedSlot, setSelectedSlot] = useState(null); useEffect(() => { - request<{ config: BookingConfig | null }>( + request<{ config: BookingConfig | null; repeatExpiresAt?: string | null }>( "GET", `/bookings/public/${params.userId}` - ).then((res) => setConfig(res?.config ?? null)); + ).then((res) => { + setConfig(res?.config ?? null); + setRepeatExpiresAt(res?.repeatExpiresAt ?? null); + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [params.userId]); const upcomingDates = useMemo( - () => (config ? buildUpcomingDates(config) : []), - [config] + () => (config ? buildUpcomingDates(config, repeatExpiresAt) : []), + [config, repeatExpiresAt] ); useEffect(() => { diff --git a/src/app/gift/[userId]/page.tsx b/src/app/gift/[userId]/page.tsx index 8c2abef..63a8b4b 100644 --- a/src/app/gift/[userId]/page.tsx +++ b/src/app/gift/[userId]/page.tsx @@ -93,7 +93,8 @@ function GiftPage({ params }: GiftPageProps) {
6^0~gq`u>$H^^(=K+}Mw5pb4Tc+>&6IYgE zDi!%u>~l+DnzqTt+Fia5b<*dGHL*;(F>l`sD{0Fnb4+4#vy@Fc9o^=iNkFY_W8)^AG%r!YgUIuCDP!UZxW%BhM`v+ z8r=%`q%A&1Pi{r=nw_bTQ3GMzSm^1JI7Y5A$UPI#oK&b#tGz0Acc_5&8I@Qmr|WY@ z*eZ5tzBGZ+#RKF3XDDqRx-(2PibZ#ZDYj`rec&2KPM@_u3^&``4y z6k-AhmLNFqQVC0KMUQu9wadVs9!I0u07h+~MXjU9X)+XQ!QA^Kqyoidr=b2PN)*7Re|Mhnnl;*tZ#CGUfsYO%({P7RCb8t@R#XGm^C#*&b1y?z?VF0A4*1C4D_O8Th*1StdM3{{{e`Y@=DuCVi?Dvb`*u%P z`LGfWqgWAE{F;PYvQ#8ktD5JvjR}gTvMJTF;W>EoeX3<%PsX;V6)&r?V-nBt2BxMTqO%Y4M~xq!w1x z_<;M$uYx{J_03we=wWcj*WIT)KQkCF2Hx*HKb~~=^d~yb9rut?lOd-WEv= zqH8riha?e2gdHEivMGD&zdoDSEePHbjM(Q^IN~F{cCf&>p+N5_;Z;g}GHWq)$^z(m z->^WYX3YZa+!3Yf+Qo{~zkZx&g1vbC6f+!irF}k@dm8vZPWNdQz zF>i(J&8`k=)jqW))@BcX%*X&KiH()@kD>*RiL=YHAJWXB{J`#w&4_`!!>~o@^YBr1+fBcKD)6`BzGiI~rpmW6ja=bQpY4BkM(mM>V92`0viig6s znn$3gpDZPS2FLS=<#>)gpS5H{P+c`AEOt@?V6?k%cX>EH1>weaB^`FdzT~5cGED%; zH#sE=kMW*)2hcs_SHETXf$|xec|nQERV_WKyxIX+}%VPzrs%?SRs{XSUR(AP1R zZM({)_hrxgSdr#_M4?lb305C*8QBiJ4e_tXoIy>1U#qpB*B~yuuJY+iWg$LX2|GZ# z%FBade!)MoZR4Roiw#}d4U{5l4dU$l(T1TQjnQ90hsH!3`fio7Ai2tuFtk_mt;&Xj z_jorl9@KR8(Vsj+SHBNIo=pa{rz=Q&KsgYcU?q!TxJ}~=X2~ey^ zTsnE0IXXb%3&d%RTZUZXdFU#2DiSdyyLq~2x7aw6Eo)uH8N&Pr%1KaA&W)9TAfU_B zi-hDZxD9y1Zd=F!-{K=zTpZXEJE{g3tJxEo&pZxJXJ#it*j){)1*f~32nM`f@%q(K zCPaENq0A#k*dxl1m9T{|-PR=Rt_gLQJVI;V{l9mKPlC=v;S20urgcXa~lrFTN7 z+9+1}$H#gb$YJkh6L}sS(ey-o?8rM-`WtW{k6evZV8}-6WXO_)8~7fKe_XT2$DhJt zu91io7MSRg#wVp1w7T}7cDQ$D4?5rhrdVy<0v!ag*y&Trg+KmmGQec~I_nzq(;onP zXaaoErCUD0St>~)cWMOt?BxPvr+hV_kTRcg5l6lJ`4kWwq4o4~ZRR=tK~Z6QY@le} z{71zs%JiMp4*(v#KVH*mRS67;Tm`#Y$wklNT_2W`*h}5=ekgF^LWb*0r_f~BMv{Z97*i{A|@t+V$;>d3Hng&Y{8sma;oNgKWm&O@|KY-Cx$uc z6O$NU@wCX<^v|1MU1t=1^yiQO!Qg@y5eW~%f>BHFP z0rha~fcvjfZc?A%UsolvxE@qAvyJBzYOx1baJ|~RFIFwX67}n2fMQi~(=T)*1#uEo zylHgH3VE=xM*T`(!wwH!E$0>pSsM?kTJ2yyoH>)*=;|IGpZ#=12m8PPGWWaBatH`D z{PSX5zbvz>YA^=;I2N|C!i~JO4F_Cvq;;`r_{S;|oqTln`c+A|<9g+*nDE9lfpuP4 zabpOp_D@)K19F;{#kzo;KG-ofK(Nef1y13#0YSru$ro`ycHEX8cpsL7NHGl+4HZ#! z)9*n1-XpvA7AK2R4_2iH>W=@4b}g7TE}yBn;p=vReLf|?^i|+3>jHa7xA0%|@LMya ziKnaL>%2-8*EK5GNyArw(S5K(=F^R?SPi3AqOJfMyGczeK6DoJKREEl42Cm)5eJKW z4vN#wqz+DGK7y*4=+`lH1>p_8p_C){+fc(U`$v8veQb*72{4x)wQYhfQ+lum^*tNY z#u-)*{|y!oYEo)a6i1O@>3p2drciO+Q#DId+1BenG`>u|D7I#Vz2P4*VHP9?F#Ta0 z5-eBkVg|k{kc>*nU8cWA?!}Mf%&)U+i9Kb2yRlA}$M5G$ zClFOLPsY*1riD4SLZ|-X2w5uGZj^!LFiJgD`bNjQqI^V+Hx6KLG2?aaq>mc1`388$ zyAo4dUq{i0sYWWItnquJrAMy%!I)!v*q#}!z|Ws$qSyOAkexwfx2!j%9N5PK0Aj+X zl$C6>W;Bywe<@v7zl?~2>-jc)Bh2jz91q%-4cGqiK0qHJ^M$I#6O)hn?O@@BH|Cd6 zw%_&r?_jaQ!^*lp7qqP>O*mrMg#jYA^b_A36mr`9e(BF z=O#~XB^dP2)-3?g#C0$TFYWSVgVy_0;XtxLPP1IngPM$*>@SZBiXSuZ0cqCL%s^xX z7{(SCf=O?aSw|(Htv6T6v{7B*Yi-Q#R&DM}_6z{oKTym>z~onKLO{3Ncn?mDQRP<= zKJXFh%%~xctqr~NW6m>p%t$E{qZ+>JF6>gRRIJ4Io0d?CeL(eIn4eGO0b}#+oaoa~ ze2W$#?YGJ5ywlQ_9?Z8Agg8r0v;&@l=eW}>Gb|Lptt(3f@RG$Aoh~70(n6Ew51|LO zgh{Ha49a6Czi9o|QyUaoviB6jB252}Gi0eA#B3M%VKYs?q0BQN23#>0+{qNG?!I$u&7}6*0PEW>K7?bmaYyn~t0);**8-TIy z>&p6rSvT2^8EbKg+5e<^a9Ki>u!R$0_+h1F2&8g<3XnqzE|qHz{4Csz zJhki{&mYa12qMltp&wdpR?$;6CKsMvSzHLuW$r=cchvaT&a2*A-T$KTELK1EZ#9?# z0flGv``G&-PJ$@b_7gF%3f8omOQ1gA!C>;#%53)t(~s2nqjG`Wow!(n$)%Kav!!?q z=8H|bt9HZcD%_>qTxdM!EPCOc(*SO6SP8H$^j~3MvYxJioG&Bx7Zb|!KhZTyrJ3%; zjC3sZIKviWu$Kc#OHbr~4FXRbC_}A#|MCI}R<{U5?#M!sXo!D630?c(I)Hpnl-g(qEegYBITJ<{m=Qf_MxnYAru`=`KH!vM zR$%_E3W+ohy>R@&WI!cwc|N#)yy1i%(Vq{wSppL89~^Qpd4eD33@SFuKP#d5_E+wq zqL4&-5d1oUN0|-&F&&U|58M{bauO?G|0A~foVl&WxTzc$BxvzBM!(mp&kO*&PQ5g{ zah@qLr3xV<_KSAqTMTCHcQLm!YocUMn|C`q<6tg!cT`=g} zk-gzusH=kmQZ->K=`7^xpu8dOS2@JGA9Z zp@cfb9vAs5AVll|3nQ-ZgN62;*#{ZzRL|zoNAb9Y!wh@>v(%~=WJE$MvA~bB;LhO) ztnIxn=eMc!tMfS7IghU!(%OKBJ!o*yk{Q$Gl;sx)@7QWpnrA9Sq!JJ~sJ=R z+AEW&1pJZF(l&l3_5Wfmg~pq)86)|}YhuY=B3MieeAyr}77GvsSMtP-{a-^IdV;~jS zAhRG^*wx6v=w!=E_C~iVRv&}qZ^nuU`vlvBZJxf5Fif)qS(xon&IRo4C1{s1I8%E_ z+=`JUM?P5}b|wb>`iHJ?(9J2m`LVW}%0VHfKyj@$Oq?HI(;%!8>ijCD>6EJxRkEqx zq}3V5vMIk0i@yt<2s8|N>|g7w_$*>=#4O>%R&)8hX& zSm|IJcxRYyc}`(&-m0y}H-f?1UH4r1yYXQ#R!h>M-A~5+MYzvjmD-z{;537&{-3ZyDH8;CA-%L3zAz?b+Q7@XM=2AcZ zU1R?yB&F@(pFzEb1r-%*c{LIt&!zqCrJX}a%b>0D>u-Q5anb*z5@>v4K~Y-(eci=r zF!}_tQ+R@Z(QJd^s#-NRo+|bHzo_t)Ves!+#JLq>SSKDEN?<=mtliF4ueJxHD&H?M zv+|SjWPeP6gMCeRQ*({O7ebcYB{TPMJ6ErOvELbkX8k4G4f8)GB+6QVs~>Wy-k>3= zu4kYwP#q7e?Za6aB?RqR^1MjE-W>`S`&S@YDiGRE!E@;(p<12@ z$~3fDVoUrd5@zXSpMN)*{wi4kT!rX|-Zw_DJU1M3RIiwk5u0d;ypS`%;$LyXTnTYI zo-?>k;Y4T)V>Vj|xaz+qZKX(|NclS`#QHpCZ*Rdba8~wfL5bMFsHSJP3jbw8H{gxN zrXHcv`-+6S+4QCg-2Vwu63s{S!hC?>LlXIG;<0TstNR>xh5zo1GK9$F_vF3M*h`j( zSVq9uCZ9ZIsFmVBfWq~3lk!*&2Yv$7+_vc38VY{!KdQ^ddqRpy#7ZgU#VToCjW|hL z0c?MoA}HS1l%q!uUXSeK_^q6-DQ&9dll=Q86OTM4jup<|dn6@`Cq*%Ys{QWv{Q-k+ z7SAx*$iK}eOEox2-73qZ@E7T$xa`Ah7>*Pmwcx+pQrZND5&Wt4QSq7dIjQac$;Xo} zsYnX3&B*?BZdeVDF;f!rUs3qmnsxWw|JUw^;{X5gza#GdTjt-c$N$|i)8Q-!;n^q^ zjX4vvxJw8%R15hSdCaL$b&`BDx@~nB5Grwiq^Zff)@clN6*|Hg~ZBN2j$Qf{cLs|gWD8-}4i0K3R zG#HKM7cgoaZABioNd&^p4NYzPDON7zDzAbnvq}~f4)>sk&;zLGFlK_CE%ZnGu!TA& zeXEayp&iEF7C&tnVkcDmG?w^n==Szzeb9Si)*RzPU{7qgZc~G_=WlY z-0{_2IgTg7D{KU${yex1qOghjDlOm}OORwEIx=?|RE>o$N`P&s1!(QWBk)J}wLlXH zBo(lEB#^ac3~Ol$8-N0_#?ZtyG4~m;uh*zyhf$#(0Y5pyVnJ8eMywr0K{Zh?GIHAE zwF89M@@@?mx@9_9Q8UdcXhu0&3f~Y1C(b-R?p)|%lZ#Myb3=a#D!T#op_8<%B z8I0NNB<$+!QZF-hyXRmmgf}$adHJYd$%@vA15nwIen*SBh@|^HdCiw02(0FJRThP1 zoHk~jy_a54y+a0GY1lg4cTzBNOPYw#EMS=Wj+0#s1f6Mp7C_@Z#w%x_i68WRMV~KBFA-?#DWbD_=6v*$2 zsJ1!{z1y+O&Pb^Ki3LA70bTNfssyK>Htqw{Lhv*U&?FBdw-7PkLFL9HYX!GNu|M*) zkV7-ck)BBq5q(ErxH#LBsmR-Geh8rFERykO{- zCw(VrONP8S-R$z|udD$6GyytZ(&#r(XI!BPxKSgg0}HM^VF`~w2nL~S*Ffxoqp8&!xd&$+*~teUtdkyR$`nbhuE;Txw|+3Lni*n72w?8=j4~pbF>d> zh>#EGGH0P(!*4H<+_3etu&SvrsEqR^aRbKol9LQI87m0){0m%H4T{syl+@yr0|DYJ zVdhNYHU|+1{CWnfB=j!O3Hs+Q04O14Gty>!g9G?sKrZAuhqw{Q-)TFM0wsD>1lvL| z6qs;ln<`6}^;qp_D2Tro#d`0+PcU{eOD0x|opeVg;6PaOm1dx*o71$4i*qd<$muO; z`{`kMK=F3jpRU1!DO%p(;M@DZ)U$&nN2nvf!F=k}rNQa#A$YVIt;5Uns^ zgs3gP#kNRo->|I=mqRcC(t?9S!512P^;)&bOb` z545biMoAkvw-+Sb`A+ElyqMxz=y;|2Vmm2ljS~g%9VOBfNzrLqR%{GH1v_Cth##4q z1odDhPTXq?1iYjE&cx_E5PC>;Q`mU<_5F5YYutV31m#YLm0s@`BjI-@U7MNt3m4e- zmc`8UbaC`+G?Gn}u5h~ou&~+2o7b$GlB*}P#<~mZH{!tdv&?tH_QYGige&WoTewQj z?#=_Re4L9&+2))%Pbt9?J%ctA`kRV+cov_ZUejHr^9Z`O7&ScI#aR* zlnpj(bLK|dL;Lqe#0DR*g-E@b*2M1Rdt_8i=<4lb*86Gr6r8*rR@I@Kzc69Z5Mkmt z^mQc6Z^P;8sut=6auA8!UE;7b-MP$7n0M+h8Ww$z}w)* z82*~rkAta2uG?;qRVu5h3BCS^K!)4-$|1CB^eDk^&#Idf6p&-wa05!85ojmlrUdsF z8I>=!<8*2%x6Mx;MrW!I?+d~j8bG7tue~L|k|*qC2+3YFIy*rjXg@UQn7H!usk&yup5+= zciCunPqX_4oFzhEzGm{@U+Y$qyC+S78`E8XZA%H12?RZ6AL*{fmt|ZhR>p3wQHya2 zu_K1R`}xIpK#q)(%e8l`xR-Mo*f|C6M#gy~0|n-&o~6s>xK@&;^G$q^@gv&4sSv+b zEcv*%N2-^Q zsm&I5MCw@?7{igzdKuJulcl1iPs_NbHo)9q9;~dIWZlkpMN5yCzVm%AAoZ`0J!kURDB28Ba812i%lgn8~n0U526Nv8XQk1*etwF*5LPM4^p z>jS?ZPk8M3zV!Ay)8xGr?Rg(7XhcN!u{>9aOw7W)i5CbdaP@ zRyU!#6*5+-!&9})mitB?rJl8iY^O$Mqk`&`E;MM1f`a1C^wu{xRNFTvX0S=LS8tSn zwv8f1+5xKh>p8*Xoa09bs*@3meEu9iLaYhYz-ZX%B zCj?gM!4qaj9Avk|m$Zexxr2d-ycV`aS9i-5zk^4~Up%uFIum`I$F4t`fUe`E)7HLm z=!8MOa&)(*+q%S*qGFiVYUjMhs7Ilmzyxfsv?(mh<6%~mb{Aif6GlH>e;AIdz{$RE=_A%IL@b)TpmHK$NXUyGW;uL@_yT6IIY^Pv&o6ehe5L8 zj4^4Z3UQPv~L9ij17ckkeN@@@IcZI=U1kQQT| zs!E9ohaBtvJD!`PHym^m0+Xy=uwV!B%T39z6lP6|vu4F#G`W9B%)0j8E_C3w5lrsn zw=qyPP;DN^d^DBEG?GVi+?gX*PwWRBk$LM&>O^V>qp}>kDGesRf2<7tI02}KNSYuG{2V3 zf3tGI=zkbV+^Ao?9(^%08W;b{NGDG{YKQlPRMIOn`q|f1ZF&5mOpJhA&6RbNz z?TRHbC8F6+d}JDb@i@n%#BV7QSGmpJ{#0kMUQ3{Zsi0S!-5&n{shGZkHj0vBm~f|5 zZ;Xo~0L%KslET={Z_1psw;I|6$6wYv?MDh#J!{nPLQrd|Var#0cJ43qzE%MiN^q;Z z>82LY$%5E_$e`=N;Io<9eiKH2l9z&j_U zyYuEboYkCV|A+5jPqgA_jDK=+Q1gwEC-X&^c=7UI;xr%2EmX8RWWBIn7D|I$AcZ^i zB!Ly@(;R~2lHj1^OMGysi&uR>%$d^DYaxHzW7SN%-kPA2ZT=Y&6h7mw5o=i;%M zOp~`C5y?k}qu)JvS(n&f>;6!Gs8*aM@?Bld@Y%7@(T!kVfwA{DEqNE*>kBoro|$dv zff;))%2~a7WNyz?_#3J99*zX`lZp3$+e>o{YBHZH|48=FpGza@_BiNBChO6bbg)W0 z+if^S2pWXcuJ|l3_j}1&&hW(VKXQF$%D0bwob5#EFiyH0&Z z#3jEOym!&~#+ffJs+hHKVC+W46x}DjK|<2^TgJoemN*tq8iSPk3U=rlKYOhOsdc4P zEOJkrigsz_BWb@1A&+5N+jJdDYGkAIX8kbl#DJBDxZ zT98>quO1Ov3#k8ws(_<^mL@1N zyInhg&sB#L3`l#)Up0Z-^G%eXsV^U|(5HHV(S>rP{u#n03b2+wAE4Sv-FNwmdtukN zVL7Z)v9QSIcp(fuGaB3&AjmrQcg!IyNt5UfOkR+fG#G*T?XDy@`bHRv8W5 z#?S2Rgd)z+X@1RHd=6`NAgJ+*`sTy*JfR%%x=A?2Drq+IX!9r5$1WQW!c*1s-2qTK zV7$YLa@f_$b&cX4>v*penNw-`1pI#C!1ovYXon_sMJoIUB1}iQ&m%NHr+%Q4r)y(- z1k=>hc^EuL+|UFZLs+x1KS4qQmSfZO`>`0qjA(=Fsm2i0#$lcHd-C^&!Z_vK*8NCwoMmup7h;WjH>d;rvdji2N>9tNAPT56{Ch<+a?Y}u*PU&Eo@=x$+H zO3C8Ap1n4TVERzo@=KHft)_*ngMfxZEpP_!$V0zcD{(X%!FJ{j_v%MgV?~n3%@PvT zRo}3z|Z@Q2OItRGZ50RbnuM^WQV%_ip zJ-0Pivr1^Ao;z}tFL;GrtKG8AFL|rQUa+li3Hz7k(~&3sB~~p67bjwWbg{xz>&{Yl z&K3}PEB6xYNeV$aTjr>ZGGC+gg)ma>WCVW~XM5&3NagmO;!~3N{FmpK*Y4>etjvWI zFSKY1o6v4eO~LEP4a2j-fsS4upO&S^TS|&LVrqQIh<#&5eY1`X_7to4Z4FuiL@#*g&+$t*^eCT6)*4d{_Zsz_Z z;yrtnl}c+-!FJDoueqAj-c4q=Er_ur(rIR4=KvE`2>p@GEtAT2Fp)XBz$ZBP`X6XxOWYU{GE-G`c-*j^6H*rIfXy5aN*HPv+w2j40Rz}3t6;1<>kNt zFKc5}_x^JK!r5j9^qgHZCYa7*5!x>(hIA+*27Z7F~Ha1ZBQU*xw=`ghHOpP7W5Ax_aacw?ns zIJq&)S4*2liXPUk^Cjx17?fl^j@Ta?_j5jJ$r@4x-t*3Hna>)5sH?NxW=?3z+iraT z^QHOZ8M$4COm`WkAH7IV4-obk({zAg2kkxX2p^K9EJOt5jxU%E80{j)>C&t`ES{3L z?kp{P_#d~cvZ$4a@!O43f_^9j$!mf9-E8aQv}@f)Y(f;c1&JeF89L{2e`#P4fkla{ zs;)vMbY!|Xk*JALy6%3Hn08_=ZrYtMM?HAv)T@2wM0cvsoNM(nb_&EEvN-yx$J3>W z&8*GG#Q6vcujG3|8ttZX1>cYfWb$7ue&*!LMz*$edwZ~HyzTYGt~A>RKyyC3-k62M zb4^lKRwk_ujsJo`-on#Mn~&d5{OPZO$uE@@G3Ls;1JFWXwHJf++0e+~ z>_;==97=r>j}lBsXJK5%p~(oFG`$Zo=5y(K0Qj+RxK^9)Y_Vo_)<@annUJ51o1);y zVQs@iyHXq-wt6~K%kHdP#5dUgMD>(}ZqMj0GW zU+RozI{ic38v8bOKi&Jwunj-B(-&x*mHXfl?(A|vKAN7iMb5orX~cK-l(?~qIuC6OOtT%oLY+nC_ElMM zX$ob|5`IJm7>v1f-#iaKN-ByiTJg@!EsczO4a`}b^S7<>krmvvd66HXwtGB3SCZx} zJl%blNl2H4O*cRDN%myn{M4I2n}pQ=!!%_OfzfGF0}HYHPpOQE{qzdsE1nunJ%y)0 z)lJLv`8h5^UrF3tlVztO3%(WYW+`?nux49j>`}Vo)mC>mn^%fNk#vPAr<^F)x5dPw z>ot1+(*S(dSO|A@Kx4!@siN`Ydr!IL@5Ygv?DxpjNP0AepVDW8R zdTn_bmt;^dpWP)0%R?T(B0Oo8g(N-!V^M<074TA5FjtI8ON67EXrJ;|4 z__^x6u7_s5qpmm?Liv5r)~|*#N~+4EUW$AB!YxrJd2eUqhUe;E2uUwR->JPD5XgEp zKo5M81<8EruAlcqr7;iCejxY8k0<4re1MAwjiw&syk{*^H?LGAHhe;|k{dbwb{e-~ zs@^+0fw&99L?2HQNdvKes4dx7cPycad1!)xYMU<#1Dk`XT$co3mvEj-?{TrOa5!|m z%bdd-kqO%DLv@IuY^N_t(xT$^ttbNoSp8jaZOa7|H+9*7j^|{}ULTaE-hw`I$!*d} z!rchTeXD$TR15ZEQQEr;pn9T761e9(FJvhe>Kd`?h*CzLY<_>_2z?{}VI+Jvsns${ z5Zab^p7%qFadu+6K;g__ZYeMS3{co+8N9rHH-D2$@hBv{=wsy#>U4uVvFLii(BVlL zL)?md()KK|Q@zf~-YE*F!$0#Ikik?C&TePoZ-%?Hgf=4A=VwjnBwQTMW?tasSrdkn z_>O4ajAAa{sni>-pNA-TjY#DSpUxv!BG+JIRx28^$PB*_;Y4PAmcBuBhm-Lw%)n|H zWPMa9n4vMP5q?_t3~;B};V6;*t2)zbbR5>J`xT1VFQ{ zAL&=OXJ3gd?-zuU>~rb`Vi~Q`9I}-wK3d0-n%SK2J?9OU`jS}q@vfAM6tc85RKb_iH;hy$AjYF!0SNy%5GO|9-y?reKVzs@x1NuN zaH^B&v#oA;8iqP;@!Y{VE8m3Xo}E9b8s$*SrM(1Wqm6f2#(SUh$jPLg2TGtiwXw4A zAyew!>1awX2(snC$vBdQdLnQCic%66o+BqL{HRFdhjTw&E_tq?Hjj12kx)s>Ij*jID5 zmCSc(mfr^z9!4&&7b1-F0wm_S1XbA`xs*0hJGPpE-YsOF4{?ZmVDiu9vj9~be=4_O z)KBx0x5fXMKZ{N!JnQ^mO0x9f7%)#&aVXq;ZPuS$5(*EXW& z`a%N9^pWN@qH_0?S%RepAImr*Cxw3qd`Y@8vEIi9u@f7PqbVn*O6fVjhoB4K(qxvS z=g}U$QTG2PN6^#;H>VVigiv2@H1reH3h|8Xuo>G(<1UCKmD~4FogwJ9B+M0Iee0kf ziE|s@jmtGyhZ)u#k4dd`ppCS4qH|AO*OEP+&niT8`dpyK576;BaU7jvc6J;oRfz>A zDfN=L68p_ukK9K_K4{9%4d|KWlYU!@@jQ7B*hD43wy6pj@R)lcq4SS z2#dweYD_?ae8xBUnZkE?N$H5;A*#U*bz|`Rl-CnN8IGiA8H@EeWn#M1J;V1qDxJxGtr^9B3FZt-74kPnd2D@9! zWquh6BLKogUixCY-*Fk^G)J?9A2u2u}{{T*6)uh>(Jf@7dGC z-+Bh`H)mqZJ4A{=%q%Et2W@RqGx)tZ@RTH0QRcTQBBL7(Gs3?gd5J{w*;ZDsU<7K+Sl{}(JZAxUw`Kq*J!0Sf_~0tzUjW>QIpcy09gi8E0tZL86LswTJdcrskKne)myX zA*j0DVC;F_B$`-}qe^kl;5^wH=^yQKE4e7pE||%wusBPGp4f$%Gg!ymg=xDMSg@!5 zz2bR@*L_!S;;*lXx_KS3#T7TNDBQn?DC-|_|59=S5DtN*IF;BrmmlVZnC=-wE^4CW}99BbLKa?GOGd578R->@uaz z1Jc#6P{-KDzBQAmZ(YQ>@Dc(Cj9LeZ_=7EiwheY0<`zY^ye`Zbh$Uz-IL6d6n@Rp| zDs{qfyWsr-B)0y@wX^kc^hEqzu(!9ie`@tzx8P4T$z6*9xb>Ja$RFJsCJmYl62S9KaHqY$cBGFi6?TI}^gxN@*%zIK1fr;VEwA@wIzig0F;ucj|d<(V5OIA1p- z9RnlKQG@Vq^OJrABXO0_J{ws*M{fE)d+LUv=eS4~Zg-^pRw?MdqrjA)*JUdTR{4cy zv*?*l6*mLWQsnpXT1qVkb9>$i_@(=5|CP7l4&9EGw52C)(W+eVbHqK;}%1zu6$wIuO$l$++lWXhL zPIG*r^jwPLwSLNJQ|V}cWINz|><0Af?5#rNRf_7!&6;FClI#+%64e7sO zH~r8!H7eLliZ-Kurg$UDEj;K%CCBiRl%$tv05vtYr!ne!@}=fyXSq;t{nAWYjgO(8nLa?`=bm~Fp3D-~A~GlUg@;G?g+a|DF%{bJE(fcz znJ$*&W9DO-K?T&|nSc6ozu=bI<}qD$z>I(L!19^6%B=Q3cL8#F%!@&+-(M+jQZ5o} z7*o@cNs_odTzq9Ab$Y=kDK6IWx~8f$$h=&aq{d$Bq0!{0q${-3tq=`nAHPkO<2Y8& znS7zG-H=;e2T2(%Z#LgPIBEzaKvt|5uoVt^OB_xrRkoF*ou6AW-{z_iXoPKM6)L#I z$l>RMvgwi1hDtbD3)8l00L>l!?ZfSL6 zc}8Tbb&Ak0K6$-Csfoi&e^}Jb4=zoHR>|Wy_G1Zj#Z5`{>l@4G^0sN`hxa&+8H56f zr3xa(P74kpQz|9~n1O9g4H~a@^sHOBx%k3ymfA8tI~`l3G369iLoL+&M+i6z@9Y2q zAqp|1t#>(X!=dfz*FwiYhgzCqXE*-yh%x_=cZ*XB9DMa-iG+u5-D2~$Ar23|D2P6% z_aA-Tl>*5m>5~{}!e#^Ku6y_-MsxH{EWikL$}`qG{jgo}7rGjSiF4U~tKK;o$PUl6 z^Laakn_r)`;r=)&zv^2;`tXqb@)u(Z7*qTw0#Cg*LxP64yQGSetmL7_Sf1wUlXORP zT3dLM4NPKezD%nxo3}k+54#9C)q8$goK+HjpUaVyX0-c&FYIJ%mFc*~FE1lzjdKJUsyeRJYFL6%DciE<^Z(Cp1?F)Ij3d;wq8xeLK{HTKnWI0|2%hx0Z6 zE+Av~f~;^>UU8FyFR!=)m)l0)-r`u&Af}ealTM^2eLeFTH6k~AqTJ_C3fmcNZ zq%k@pq*(RGZ?~VqzVXTSB!HUSFSX>%iX>8 z0Ru`0_W;;r`GI@0u1$jDan`0j2@Nv%t?9QLSg=pavNw)GHBbb0`;ED)`@IK_u08RS zq+B}Tzw4F24t%>uW8Hgl%pRovynn#>Nnu-WvvRQN`H|CiTwIAs^Gzf&@N1=1k%Yju z@l}0Fs3O^y;qeC%a98j z%AxS(gR5WlMwPtC@LSZqo$rTZqE1bA*yN`PTN!~xzjK3mpQ8giXQ}7%DaJagiEn~W zTA2MF;-Iogr}4>r>1>nzxiOYfNhOx%4u){MXx6=tcRI&UQjN12u9l8dI%j9)_t=h= zop#;RnASP8)0}`+3|WS_Zgfv$zM9~C$A;_Qi`8YuYe8VEK79RR&QLt9(ocEvjKdyh zUV~ufiMX{bwLmbJ>je{dkh3s<9uswgPryZCB-5Xa;V1nwfq-0ti!K_g0m>0I7$$Xx z4UiUnGK~LKKVPkmECY58q6tT;!Me{DgfMuULElc%iQ2VrP(d^~$|Qg|x5$JD8G;^a zoqySkhlAEKpnrquI)sk;cu-lsFrXqhxIe25+bF$wYleR4+L?oO37f9pL1!UTnlYC$ zsLIOcU6G=Nc<+79M)td}T3A(2;>7IzO=WHNbaT0xezFRMhH5JU6SlK-dKP}q#s|e2 zZ6}o`v@j}C|6wpUx0AG=9_Tq5)BkDjtKXvfqJAj}VMvuODFx|{A*4h~MMCNB?rsn% z0cjXgQIL|3VMu9aknV;d2N*il3HLtF``el4oU>=|z3Q{pUTYmEk_(yNz$Ab; zZ0~lJQx$>_8?^OpVu`W0fv&A_mIkeeO}*h!N;YeBh`t6Ith-b+pph8jRN~nmz4H{j`Il-a*HsK{mpblT&rrPO0UGKGFenbv$2&-l(Ip1%I#@icgN-q^}sAJo2TaL z8QYBJ@#pjO25s1y}cs;DEHKk|^p7Y%_lNqc88u1o8LAXH}gEV!X&XfU0 zb>P&*8`9q9O@jzrFg7W=mY;(*J&xck*VFRwcQ92sIF348_3q%zVEVl=Ygm00bOp3I z7at4(nu0D!yiW+b-O+B&3HFaL#8=9mFLE)fC&tq3P7)p?hbrz*6P z=c#NW@ri@S%Ryk4zVM5J=9?iqc=t|2{MQv1!BhP#rrHei`WzP5ZujaoLnQR%SmhAL z(QoRQF<)FKqYqj;TzBG*H8X>Endkle_SR{~ao5wsrT3VdekA8~A)OP#u8Q5y}^n~_{GEsJY{(Q5lT;3oN`1ufd)voO6+hYtQ@ripG_fz4e9|?oW zH`iHfPFSLqFBwn&;8r@Er`+F>A|4r3hZg(LNBVMpig-N7{)^L=rJq4`_)(!!L~ED# zFi~MORJ8l;?001<{$a`huJtqw)WOBgrG(S5={QYptDG3T~z-7>^&-c72P{_ z98um8L0fEEUJ}kzvI_7hR3HlJ6oBKd7mxg4N7dmXDfDcpl7T*;8PdBa zqOSR-j`HksBnk1U2h49n`4O75M#|xX1|{l zr_XcUe^Si|{n>=c4WS=%E>^OmkR0h07tgW$k>ibVa54mhW|@I-Q25mwo9oTK5pH%j z6N=G&Hc)x*-IsN%zXKC^q`%y8U`yEi0KE$H${LYfR>-|xcuE?N>(zTj(v|EHR|{4# z;k%Km7_^_?vWfMzNu#{ZH?uyvH(!r|`{SOi{4=JJiOV*>`OwD?Z_ayDg<{41lj#G+ z<0p766{{bZ`#Yr~+E=mxyY^>y?W>%+DU70X+5##rfv95?XS}cH+|v?=J&aS#oKMwr z|7;Z7Q3WFWVDBJKLltV5#E#dZf{K%FR@~#B*I$BX^Bcz+A8_Dc_6v6*8sy;%1T~O~ z0n*nEwcY~>c8L%2*k1ewdY!}`gQz#?;CM+(}odq-t(+COK-?+PKTVMIk&|? zsIUQzjpazTEnStI$O-W?A(?0x*^}QO+ypn9#cn6fqwN}%r1?@`Ipi^mxpa~CH#ts{ zC?^_;cuQpVOgEaY=hW#B+a$K9!UtS;-|I+Wfn@nd>5f?W#sJxQ6aUQvRN+hAFL~pZ zxhW0@_w#EiaAUWO%{?bvnX8)f-k2Y&qz&ptOnLqwyZg{>r*f0&!J8_k@hqHkj0Yq> zG{3_e>NI)c+}RP$GbPCgmQ*ao`I{cZ_mu29g z63DsBRpshBpPypGVuLbS?|zvqkk`|NmAo448z9ZuEW}%-5Jcn5yuVM~8kHSmM<%~+ ztX({Q_w3ln=y>CX{~c_FFMh3s4yV~6b#~v2W6JEwQ}vMF92CXo=A-=0dcCHAIez)^ z7DMV2XE`yO%CSdP^Af{(Q!7_U*ZHo&rVa4MJEX69ex$)3eP-NI(qesWqH5>EBj!*U zOStrs8Ipm5D#r5_1r%_5#9Z<7R3*e>(y$cssb}HPcb0XV3XRED(U%3qG!2b8Nctnp zE%OQ04iW>)zGKZJz85LEqEG=8J$6q=PlHj(Xk&P9&>2ifd=k+apOWWI+{qJvRa9yJ z0gyFINzw9%%7gst1Rxz!gI>R5j2x&Ug-zE?Yn9JV)}s3izVil&Knz()d>R~^40ZAS z%5xG#snI{Vkm`-)71qBEc^Za-ARJH2U+2tIoq2E@ExROFj@?h^zM(*M7R=n1JF;G2 z%d^D1w(OSB$Xejlzy-H!&tAp0ej>^+$ox#1jst=@(xLl#5qn;v^LuoMb+n82xi87RsAI)EUy;mIcUAwlTX&RiAAu2D9Wadp;x{hEWlsvwTeFUFKZ=;%jy_$y z2dR9)*Y05uh|p@42M0SV2fw1HUp_heAS#^5jP${?qj8m{u6rOo#9Wf9)_L`rBTtbS zT<(pN`KF+V2YbHe$NW^MZF zh4^=35q2fy_H>JZ6v5=`=@EGzeXE|r&PFY1bRlTEiw$|Q>1hEX4O0tMLwtntTkv8q z&4){n7|l4?-uJT7-F}eV!(|-k)84$4D{#*_dhNIdb@aYNxkBr*k#D*ySa}B5!+I`) zLvtF(AH#}#FTWKD^0^jjeM}o1T#h-Tyd#QC}X1d~3s_POF{HXLrvXz?yf(j3O3`W8yq3dtA z6+t;{HWS@Y;7^F@dDMBEj>=Gq-2$N6kI@E;^!P^L8^o_OF)4&$=qz3z1LX>nE+>N3 zPCodsEyDC>ux>oDDy~N0t~g6ySgqO{+0*5{ z+eoemEX2&~b{OzT!AR0ZliG45L~q)?6F$P10gGP-wl=g{&jsP3iz=EgleD>xAZuOM zDSg^y9Zu1+4Wd}Rus-$v@VsJ9Dpp_s{n+7INRzmEfKijzpKjGa7S)p@^5_-9C{voX z|9Y8(-);!zZM;@!!!7+|!LVBoT3%ZDz1qj#4oQO`9q>AK-QaI5i)xgtIrJ0rM;$up z3;UVimV(ml8GLwZ3S#i4nDbhg79bSG+8?uo^8K0A6pxmp^3zLgiY!lX$tO^D5P zej_r1svBFMTATuwCMbSyk0g<5$`-#ASIFGZA)iktcj&M6O---d49X&K_AxwTbaD=4 zI+6>YF$LV+zEX#qy_xOx3)G(bAlys3lvYh1R$(``L}lT1`n8TX)NkfX-|-a}-V=?^ zaI-ne?M(W~UH8Zh^yBNW$I}^~(X*i|^_7lzdPuB_CFR>}zK^gHhvyUal_*ClyYyjD zn1@}Y(SeSBoHSXZ@Kwetb);gFfBmEFK05g;SIWMMy5Nx}%HGkgWzVp-LPF2Dp*bsk zVN&Od_0Rc$%--tiK?Qx|pv;VtNDNycZOMx-_|8+%kJ?((FJ+0r$SrJu05rVe{K7bJ zvC=!`YAsArL`CFyU3d@|qyULAcE6>adm~D=Fl73`SGnYcGxGyEKF^LBJ07KKz&-=_ z##bI{X&k0GyzF{r$vFwJEYfau?uvDd&eJ^6ldG8T0)W;m7F#S343C{Phj-`oSJPLt zUX*$~T%$t+>p6s|fL!Bf!o(K;jKhgf_v!a$D;ZkK#Yu#>MIIvi@LOg5o{*qobxqbC z2UeQ%deU||NR#g^v<`DZ!a_+Sid|EsN7X){fiRY?;JI)dn#H%T>-zqBpZF@piTsEZ zt~{q2$taGw_Gj{>3+y;dZRm{3n;X3gX&2Wd+#XqU4J@=x2Q!d1DlSVVAkKku;;-X$ zG4zB7c6j1bOu&b))1XeQWQ~{)#9gw-I;LZXE*TE;WGB40M|NA0(LsiQTIPDQQQ8p( z;Xa%IQCtcM;pv5W{?;gOe`u@tT+1oths%fibCR_U&t5;AmAoXazN5B9aOEh#V>%{` zC;akdRB2PtaCESggt3Uk!`!?R|A<9@$81IU7!Uo)?mqN%>CX4DECKg}XC9Gg``x}4 zbv$i$Ua)m<&!VOq8D@g`SJTdjtmME8^5q5#Z0nD!f>8}VIPqfIPvZ*F^R$KIXJZZ? z<{R(_4{6wQsUvJ$H$j}VzTYE9(qSDfMN8pC2y`yEDJ81VB;8Ai8M|871I?ZlJ+ej! zt%1-%$@`X2dPV5uMp%*_7+^%fJ|7`0#FU{8_+BXw=NgfMA`^p25*t(7{JEW;lN(L8 z!>6nyW|n=Xpe<^iA5p!DF=AbJ{o;ObCC?}%5?fV!-$1vbVA&o+L!i5~MQ=0pTU=T6 zU&|pCLsr4aH?u#OPAVz10&i#+r8)*d&R~JXsp1^7jJ_W^+i?gduiDa32oT`6n0hqs zftjN6)N^CWfzC9%+ZI)Hdv#4IC3;5JVGGt;*Eu+S<<0p^{eo$2Dk)h&#@`9O;1c3E zvop(OkLyjKGZZG4eA9W}*tuqiEm3Z|^b5Bpu0_LLa3It8``H z*%}e%vCBX%&Zn%d@HsDMd~$xrndOFBWHC*pFJt|)L64qFaRe&g>uwPmn>(K@f=d9m z@BH3Ij(MoW&Dp}Ert;}Qh;r^!j^gG#_~DQG`q(y9DGP$Gii6)8_H&AC(Pvp9*0n#D z6!6FuD?kLT-oCmf$y|w;_vKhh(|&Uu$%*VIE;~bNXKxY|@uZrHE4p^G+_h4=k*~Gd z1^TKsEQbIKkF5mP4m=#1`B#Nn&w-q8hH9=qiDcG7ZZHv!7&qr`M`{tz!wl}p!g1hv z2z$a3Ca1n1+`*~yn2jn`f}VU;W0X;LWOL6fpAwxoeI{+B9=vwdOsTm(li`=xu6r$t z|3sK*9=$ICsEAk9WlC`8HixnM(x8INi5bZdp)<#yFzN+Th)=EqRZ0e==ENf0UNok9 zZrrB6Hhm;Dg-zh!-%P`rH!SU=z$0s`nmq449!qjQ#o$sI|bOe>aTdy-9 zi0@(gq=dEu-l!RUQyr>}C8MTcxzyiIoV1ppOk}%>;%1cwP0fj&%<=vhDx88_qpGev z=p7Smo=IvUG!Mw5JBkA>9W!~fGWNgaOpJSE5?)tti8EVL%^b6udn!keJmx$sGzxO5X}!OwxUjKu4xLdY?m zY8#9vGgy_85FO;(J$>I-kA~oY=Kek`j=xpU?un&wXpF8xMt9532qu){%q7*{%<9V< zs`YS=Yu(Sy>jdat6JUUL{_?}esX(mi9FsM39KPGp;c4yxT)yUjmxlaL=99mm!`HG0 z+`Afz0w_;5L?B6Vd!Nv zE9L~y7T~Y8V`pCA_dwy^ncw_NmDUN{_K4fPSuf|fG{g3HT_3!)?pKwc8*NU2xpkO} zHv>o$(}}mgZ=YJ~K7*?~*Q=X~!;FBKmfE6H{%H|IyR^WqC4MB*8Uh?J-;#LHWmzbY z=Np6se5lia*75*49GQzAte^@pf{Ms9hUp*#X%z$%=Vdiy_WUIEt1{y8pN35+Qjfc2 zkbS3u5{_V8t2D=MVhP*jv3R?zVN@-CLW9SHA4w?MD~ zRnO};ubK5FxpQ*#?@+#3tSN!eVxam2z{RP(Y=X^;`E@-;O^o1~wFgb^AMG*Hfa(uV zxB9PZJ9-1ka|s+xSIC+@A=2Xft+R5zScYg>(}1%;|I)iFh8-#hmG8cb?z)x&@F#*U z6sx&Kz$^Pp*NA9J7xOm{ky`a0w~lE0rF18ASCT{az`%g?ZpIZuZ&0(Ku3086x&Bo^ z;9?FGi z9CJ%=EinhWg=a6pM~HjBl=Gz3rgkyej!rO zp%*?r?C&D>UwPl)!6Wv-enfGnmYcK^ak$!*aox%*edFd0r?BSi>xiqiTT86>u2h#`z8l~4%rt=H@g{BN zDn&06DoQje9{(}Ts9!YS5&{uKI6zkCsAlc%KDRR7FWw_ufu|P?*8}(Xu8|*-C-CSb}XooZk_xe!dyY*}V5Q zmc^V^*x48r<`vf4eoLiS*YnfdxuH-gwX-`yZg#c)d_#RJj2aBQxZCPl6xw1MRjV{G zUGiRv@P_U-#^1y&)K%Ojs*m? zZi*KjWhHPIJhfJYFQ9o4w6e#hjTdiZV^20j5CwcZ6u5=@i!^Ya8JYY zQd!UHv<2++r&zq#$HVa|6wLe6$NpCnq$Psk|LuVEw;R;|FU_8AAz<jd^TIHSIV*bAOjuQT`g5=jzs6Y7MDgHmXi$)W7 zuSc|{7f4{>ANgLUe~D#sP6f}Q#l(pffK~a+{KrZ3tgw=$cf44BE7&4-0&XR>ALdp5 zG8U>tBG*>XZ<7k+#$SR)^g$y9{0-!hn(ZGpsRVwLNo5x~3B(mas_(Da=D8-zA1VC& z#ggcN&O;s;#FYshb1%$M&oS5XGDM{G4;yw$$^pbQ+fD-&r3dvyylHj}(Sc7s3xE8> zqd|VfZ2|Y4wsx^*>j?tf@ZFvWqh|Z^zuEfggg$~mv*lW=0Zu1!kDle^@w0 zQShC|_)KbBt2myQ8NQwuTQ&7v;MVusc-Ozo3qzx?$EIb^J=*hXT`;i4jkaWc^o0CF z(C_!9F)RIwWdLqZ@XxQQF!FgF06W?begbE1dHxC$I-r70Jxbh*;NvV1c=w3^akf8s zWL$Vz0QnqsFSXJiK~1G{`x<82-4S@x!pwj>9d0@McJQE1y68Quylk!Yj>|tW@(;pv z&SqbfVtaZ%@ZKtXo{QH+23RzoFz<0{l=aSz`8Nrqhb9>Mwh3kPZdKCupP946l13(o zHrhpB@CXzZvCUNlB>cBA^bD}jSC0${IO+;9fd`}gHKSbNA+NOI^K$cYzsDl(Pok>k zjx3?S>us<2h8?El!l?lYKl#-A?RMqgC<3igr81`(@UAC}_=YhpvAQnxA9zL9lQQKVG7`6rkq=c&kZsddYqKc{e=xkk%~#)|4+A^ z1mG<9Jskqci1-|Qc%4><BDkGl(^L!Ew4>P|1r_LWjNhO=JX?i&ZLff8b`dN5N5rhfek$Ik1TS` z4}WVan6&*~Kmc8~r?}mdtBZO0*5M{C_+Z|R`w#BGAnpZXf7sr{#CQL;e~ULkREi;9 zq^yoUb~=bbcf?1!8y`ar4>{H7z)iv-;iq zv%k_dJ$rd|^{xc3yvdVNRrU6wj7R;B4{`NMb1!5WM*|nXpESUq6Nd{lLiJmqrJtBK zfpeLaZbe@}_933s>rJ(DZm)G^YfCi{>h&8DNX&me_MegH?tc` zMqsE`@7KS0I_m(P^gy)6$+0AX90-q$9}NE$AOYfj7l02SG-O!>d8>wjy?e54(=_EF z^;pz+O)ReYfmqWn=r|f)js0uarfY*igO1vlCthjSlQxSp^j7`A`&$}0B1y&O!~`zM zpk4gU|DK%h$d_)}HRy!i)l_nd>Q^Gk$3wemG(2z@nVmP?{4~w_8M}( z*V<$>0xv;X|UO&_r|b-VVD%cuJ?#~LS?HR63}tIinTc%67(b6y8j2rJZQyQUpH#DaK5 zV=5{H@|xX}|6L-L)gbl-AsYeLWLx_L8drEP;`Yk~QN>g4cO7_ke*To?L+VnB<79{_ z2<#72aOABUtN-0 zLkZW!xlCp|KRm8D>^f)kih|%vH@+MBuRy4{(C_`v}IW9 zQeIWhN2>Wl)*YIJp*f=kET64F1H&B2145kPzzcmhYPHD%u7qQg|IG1W6}Is=AsNKW z7rxMYxrP?=dri{nIUef3(g-$+o-eV(2N&62i4L1A|HtyLE=-JixF8>RB_lJcYOf{r zvn?ZhkWg951~aNiJ*CM~v88QISG0&fEX3ewLkujmzkM&FcujP5GYn^#WlR^ntc=kw zaii#|x6H?MalFVnrDF2SV*d)W77i1Kn4gaV{K)YG>m!8EE%*yA68KC+>Jumdzrcu8~3Jo~$^ zqWYn9?ywrMp`x-d<7f*^9LseZEo=^Lk9PqPssu}i$HSiR`F!a9&i~l2lmfwb^O2-_ zM-S>GsO@WrYzUF<-@?zEv^JG%=Q;va!%@l#yj5lR4=DW7y1Aa!V*%D#IdcH@y|mQI zF%Wp{yzGS()AdjH#ftrpQcvSZ|yHXeGJb^*`@O1M=hZLlZ@=H;5%?DwwCoh8o7s#U+)c5)<%KT+hZ@VmW8L z{%%#ntI!H<{g4p$M5%^r^hMY7sdU#+K%w@gljw@DOl01s{VClPci~?pgf>+y^D#7= zBU5DAN94S&2N|C{QI;Yde^Hk{sqzbSRm)=nGXftF z+M5lqPmYVQyOLxP<=rIjx0TwS&(q`02uJ$VMsNM$3jyNGGfZGjJ+6Dy;rD5 zhh}<6CgdDHDp`Q*|J(d{wt>yp39InT#YUWQ!8YFX^EB;H7Ufs*m8M+_aVtAgl0$4| zL0p;kdQ8iK{N~Q_Qc7yP>V`=QJ>udeb`t&0$BTxo2HmgCsTIEV zAzYeM+|~aywH^IfuCitin?jO=X*>4b+*Ryr!Z>BfC9|XAkB!X*^WE{mD?fI(61AT- zZ=VT~{c#5Uu^V4U9MPl{`teE})@AaM*Lh35ooB$z>ih|j?6UThuFGJav-xi5^-nQP z8WhV+u)_^9SII|=c2n4blaME_$Wtm~iaqjctd{Pp?wsY1GX~VPYz#v z`KMk8qF86O7rj0|dT-2P&1fA~3&y-c{~ZvY^kWx)0qDn1*he-;OJ)UV$RKhhmxm74sj2^?}a zjQ#TLiMPcq9MXZxdrHyOD%)6Kd)o95jxZUSF2)GMiH_I6D;V=%8Py zjTzYsGlC6O*t$QwzcbfmCp+>x(ttv#wj{juIxY+#X73 zCC_l};XH|Neif)l5*&!9-CP~RG0`DYkW|g>kdMHXGOSCV8u&G#if-K=KP_J z!Zoq_sNIp?y&TQOz95JO z#gC>0qhA=16zzW(xmLKCY8)J}_>9shL387|+O$Wscy~fG&PJ1+9d0-zF1Gv@N1FO6 zySpn*3>&_i*W6fxY$^J>sw@tZ(uwu80!-2C9KxY`V-(n!9>gWlBbGWozVf5L zQIqtH#L>8?*AYLcFT9}4)?`a)vUz2XShAr>!r9DPPM0aYSP9{U+{|{WfC~(+P;OUmgr?TL3O%B~T zCDvNFRUB^-aGE&rk#0(1OA>Pt94)x-iyX&;LR@&ZYoVs&+fGNZ04&HfrANtgFDgkK z2a(^Z@uc^?AC__Id#tu_0L^8SLW)CV5w#`qr!EedlZ^m*MKSywY>t0NBxHgLYB`>w zq!LIg891mm4Ty7vJ<{G5dQDx7EdYBg zWba!3z5_-DWXf~p3i>V%N09ol?8w=A&a0xOj8-H-Vzfs=!@#-+GTt8KXh}ThEoEUIK>(a$bg*HyeKFxv*};49&0Ue@Dm!${psTRmK&~@ zT(@k07HGaw>zWQR=kjck_8QNUn{@RGSxi)D)Qmjx7y}(skN*O#!Jbs_JTwZzwI}+R z+gg8AAil^=1{#N?bGIX7m38R|t4bz>=|6f@FApCs290LU8dyDA-?1*@vFpVo(8b4z zvu3VmRx?)0+7o01Z(o0#`(a}`7KHu1ma3d-EV4;EvYI=NjNrZNq7fwopzd-3;d zW*QO6wsbU-M~m7o6Mao5s-SkVuC-Kqen@QD= z#~UAY%7(N#-^K1epLR^rtIVjd7_zy5-k@h1qCUXbzcWMFEoE2(*}w2SU)joGWh;9N zrB#>Rd?m6a*6z`T7t*FAmcpVjbI7^0w>7u!;5re6EqTV?%+gs;AY2ZXL!=R;vt6Z5xt!mC*p3m_8UwqL#tECq1XgS&5~;O_!CWR|h!J9e)M4FnXa zg7)U1-93h8?FHAlX=yL1S8KPJp0L+rY zQOiQRR*-#>Rd@~iaNRH4sP!p_ae;|x5pcdEOo3wSR!IUx42b*~!ln5#DDvLNh_5$i zQHC9-tnFR+i|esr1rNAP7mp10_p63Id;}n4v!3{|+})D2gYf_r96z#!)pTtR%3CL1 z%UKT+P2}EM9kp@m><4<45U4&TZDd3>M>wizyBtGITR~T4*z?gs0Oq98H`F3OsAKc_ zYL7zm@2C{@x#idzV&9Qfx^uo!9!jqoA%irYU3nqsNn&|zjg~ZV4|zJl;Z?G^JqWG= zb2uw%DI%+abqxqy33Tg-)Kv_$+jGBm>A5fXeRd3Mk-;TO%JcP~(Zmj(Uz3uIaD zeUynjJW_>yy(^~u$uTBB<0!`A-fxlqZqD#F$gMO^YkG5vbo%AO`-_QyWLU$))%}vC z&Y8uS$4AFkBmllyM{1ME1^Do+!9RZke0hS0i5f>LTj98G49G_^0>P%l+ zOA9+qWo}l^yus7mtEPH;pz+iRWgPq@k>`mC8;@uCoU9^P+JI>)QP~#LW5MJM6gjx`54Jq*~@qPh`Cs*CRZcmQp yNW0d#uMTZ-2ls;;Yg`ZKS)KUMRld*;1QM|@P1e~tAP3j_kaR#cGD1c9C)|5Gua zJzDNCIh!Aw7tRU>-$0<31plc|Kp9zYKp-r2J89{UA8nn$PTy>uoT(J0rKy}EE?Ib zyzpnSu>sLU8f>p3u@*44sS9F*3d18uZa2IO?dRIBcE=wY=Ee6a&a>+#F}g8dr7G}f z@CCdom7>7=6ExI6xUtRgArOns8H9^jXG#6-p7sgo+D}xJm8Kh`6ZFJm<|QVmTQ#$r z>s=Utb0C#&{3IawNjEq_P#H6T5cI(-R;mc}LGDRFb{c~gC=U(vdDOyu3-pm4^qJ9r zcLo%YeVy+81Z0#PE_f^tnKU*2?`tpapgim!h7v0;r}5 z)IEXwvKEB-3dE%m9>NSl^9FtXMN8`e3Qh+R%AM(np0ZZq?y)?2D!o>;g-%E|&H`OFZ0~4qO5CiJ~V*x5KDUJ z&j0a^Y<_&p;^NNs_JUHsl#$tpp6`QAuW7g5y~B;4=-t)DpUzFXKyH&jd9>?4y<iNxt`7FRTXk*eHIFY!Q&!YzgSSu#F zfIy#Q=s2`T>Li9RK_HpDK$aRwGGxyiwr=!yJJZp=%u$cVmj)os7+x>zc&0UJhj6zaDUqxSS zL7{}|9UU*;(hGqX&w@328EKMAlA^=4^81keXGr%~uS1D~hQe)_NHgDHys;s5 ze^Z^NQbalvMLML-CGh?*Z7&@s-APBErIE#lC}9LEMJa_Lg^Yz$yR@vRY_062&biL0 zc3kNvE#E3R9UiT%(igu|%XP}KKOSn4Y1x#Dl!TSplsIWiK>ZBvBhU@{RQlAVp&EHV zO}E+ysa{%;)_Jf|+rKUkbqnO{XZSh3=<}VWE$yDXElRAcG+#)XM~O$TPV+q3S^{G$ z&E+}^toCA$sTgwZ7r91w!o0~$R>Z5)^4`kWzAP1zs$Z^9u2C+3*uh_QRGeMZA=_qf z8;C7Aq{L{p7^|3ARZRGzilfXPMwZ_u3NI`rjN6K_NZ_*|Ss$vKCXPc@`X`aVd*%u>uC8^H-J z)1rm5axro^(RPEzTXb8FgN}oR4CoBh49cnps>d0csx3v#MItI9DnsLA;|1e$>3o@D z@8`MqGWRm)GuN9w8+sVBHI_6sTPfCV8x|QHH@1HbF%&X@>FXGp)X7z5SJKb5Rkju5 z6}PA*sg>u<+4R+%HV!wIHj&osETAt}H99u>n%S6>*fb4P^&Ka5B>A@b#@vfxybfE$ zE+;o6_xo1wN+_%=yp}PMbu8gKfJ{Yj+UQT>PA>3lH4=<6_uFM_WzNXkkl3_*3px*v zictPB$^jAQ$RrzF{nfFp1io-F+346|Lcs6M|}j3HqmdZ7}r z&f)rRr{6>P+^1KhzpcxlWKw0;GHu?g3sti#@v(@PaeNV75@_XZl^Eo(HW-`L&(>FT zP<|)G!BWNl)uD6!?&v&hGkf#pmN!Wn=Pwgy&-{sAWJob_DF;5AaOww@a5cf?f0DQ? zCB)J6X9Vu_u~?qHr33t2?N=%4%kt(BBO=`3`u-Uc#K3ZWFQu{FQHL8h|A_ZgEzAnDv zxdA&?qg2tpwjt9z3r4Mtm7aCic*KZMYIzRp_|aJ1$a1_u)=4gKgx`z5k=O_eRn}uC z*Wc}^_##v*>f*VKwMF!tHB=Y9LbN%uk;QRVz5GZIQsvjd;H7FG_^D^)M^D2O`@@$y zSUVxUhb!|(ChGc}2I~!GsL*UOaiWOGD#B$F2$BB+(~8FqS(wvESNckFeQ9}ri{+#> z+#0dF#-3w@omvLjgcdDBV)nCEDC>RXjW~E+U}~ z)kbQgwE2(Ws|{xJ*I%cP$-LVydH>EX8?|5Eiw}1$>pam>owc5|x>dZbyOOAiC_`MQ z-a498syVtG4LyTDyT_o#Zk%uVJxdN3)7FfeV?C6|9-{1g$Ubprf6f0|Cnjrflh#?r za~pB>V*QHZweZsSXzz**j2X)Bm#HZ&D*1YcImnm_w zcts67mCm(??UoQfW|C~qCZn@cvVHwHZdN`o7c_eBSxl^d!Erii#RYG`Wr3(Yk#>;@ z1NPFDQC zbi3!BPp`;dp@#%bJ|tYk;YdG^OOG23eI0t3BPcE;v?<|wkGLzAp0u1~$RT+sco?lB zA?EbEo;{qOm`N>F9C;000agElYoZ@pyoI5y&e!w2DbhIPu+l`31ILK z5Z?>D4FW97fv+_{#xEeLAJ{zu`qu!?Sm62==vo1?h5?!|Kqdo78v<-9fHyyY*FM1J z2|(x%Kqr7t#ef6^Xq*QK0|3@2fIAL&?hd>O1a?mW93KGP9l-VhaC`yiIDqC3pnV7K z?g5!}VEGUj-2&bP0WUlOJt&}%31E2wb#uVQ4Ujtue5(T}LxAcTAgCQEnFQ2xf$U*G zJ`?zu2Rs&B-^WWpKtNz%;Ex|af`WpAgM&jtLPA4B!@|PC!^0yYA|fLrqoSgsqoZSD zVq#-slao_YQc_b>ArMGfT3UK~dPYV@W@ctqR#tX)c1})C zZfeI>6_u5hRaI5h)zvjM zH9vp;tgWrBtE;Q8uWx8*Xl!h3YHDh3ZfDz7Yinz7Z|~^n=gww5?(XU7 z>Fw?9>+9?9?;jW#7#tiN8XEfb>(}t`@W{x>=;-L!*x2~^_{7A-;?mO6^78V^%F62M>e|}c`uh5xKYunhHa0gmx3;#n zx3_n8c6N7n_xASo_xBM9#KFPA;o;%mzkiR8j*gFyPfkw${rh)%dU|$tc7A@2L?SOP zE-o)Gudc4Hudi=zZcr%H?d|Q|-QE5D{lnuz0syo(97d1(CIGCdruBIH|FeJupDWvd zKon3#8A)xArN7xXrZWmFL(&2K#ye^)PqFL+E7`(~3pOzceFbIek&+ac^`-23&O|u+ z0_pzuH)bY!HFk_gQ28@YV1HC?|7taT%x4e3qz_FULg5sq%V-*Ni~WJvhcT(r#55Ps zIKdGAQ!*tF3(aPK6^gpbe0#aCKY6tM?8>R9ef@VT3flXFK&lo zoP4V2j+*iLde3Fd52p;CGlL3VAK#8jqFhFwXIz-aZW>`Iv->vR5{VLKcEu^P+;dVA zCI_6B7bPmLU%x!%#PikTp-&K>Sq=LGiPiI_j~DmA2;^i>vXMQ0JvY`oIBwXYE)h+N*5}A@Hlt8 zwvinzKX^HAi&7CaC1N?;NS1c3fwSW|Sv+f23Qrqc-GxejpicaYx)*K`AIZmW4$59U zG`r|h-=P*;Ey^|29hCC2Ey3j95rU50?8cNl%JMZU*#*ONzSuuqUx(d0z-_#7S+BS{ zd+2_G9e#w8W#$(Ggo&@Dp04uUp&@q}H~TvHYGbHexnB;dXz7 zgIpRcfPXm2(D8z&tjdx*6X_lvCt~+Am7?E|7{V=X!F>O`U`w~P657`i)iS~+79K%N zGUJ}5fpQ9u&b*0NM4_u?Ir9;uL)ED{s^pAEsL0)Go3rLjVOJJ!S9jX&09oN!kMCkv zPRhAMYkc$HxO|jR^yZs>56$%VWKx@c-<_14`iIvj{@m?{BCEs0Njz@qkPMbvqCNeS z@JTL(E3~j;2}K-ginY&wBoITkt75$u{_tt{D=b!Ze+5%H-uB*E97J>B0FTT=ig+Ze zwwUzfKX-(8c!&+|WT*0wsyD^vfIFgDXkOa*j`n{4UH(7pTS=woN=CRZI6HpdG7~Y8 zOVhRYpCn@mhILz1XtGSb&SKkU9%LrkM^HcApcmdN4e-ml@^XD@ZPYF&K;#?|G>@qf zxS1gvH?0)%`km~b_iLJF80Tdaw4&^vsVnC7PhV2vKCjl`Y?r}pAH;Z~ye2lJ`~>3e z5nKIqcR^Gh!WB#95u^BopgdW`7A>a~H;@Td6hW|4^r_<@t=%335?wrPAsUE}CE{F`v z)uS`GJ9Rou76f~|i8>5sD&y!MHEzvg*_6Ck&<6IAKh55Rn!UqtPi>Xk!9;UFLzQCreS@F>mgZ<(=xjy^ zQ94trZWVm%iItUW+i77!;8IVuuVTS+#rDY5fT?32>FDx1#7wyH;)q*=llR`b6Y|e_ z*E$0p>L&B6DEW$C2d*-!YwaCWK4rgrPb8F&=RTi;uV+p7g-o01i00a-;`-PBZmFov*<8}MYS(2Jhj2wkAIXbryqm%kM z^9eUYglKsa6`t8I_dPe;KmL@Hk8#7eZ;NqN8O3@WBC_D+^Hh!tw3o?W-vH;s+RAid zidB0t?SjkdHf1JI;WSgvAS32abA|ZR-sac^>T+dP5ge3~7t^%Mv?2_kgb zLn@LZTZV#&YB@V`8nrS-`;qt7>o3}gks|#ZmKO!LKk>^OHg91*0keHJ}juq zP8VB{!kQDI;hHAfdX=guyZYDND{`914*pN1Tg)AffrJ{Z4>!M=(wOh%51B%8i9fB? ziS8NEBTjnSDZQu{?LH^MDbx{ij;|v~l)bdqcm)5Y+$pGFpD|Ul3;usdpLbtbtHw<`MC(K4h`V+|e?UqB@3rClx{ z`2K^+3}L_Ar=8WN`R-!urWVo0OE)E^bmU#-a>A!S;iy4YgkvwSVz`kfr7wT0j>}o< za&Ga%}&)v~m(+;?~9gV1pyQ63)*3}nwHP3to zkKsrJ>kAw33%cgV@4bui1~U$%*~QD`O!7r%yM*c~Yvz8FLaFe%=(esAY?GEhboZc7 zo}mMlx6|cDndqiJW?xlS!2bk;Exe5JvXdv83djc0_RfyEUM~}xhV^7_&8~=*{SKjp z$6VHI=Ygx7zim!CC+u!oNqe}iJ8#QHg7!I}=C(KGx6DQpnN0-LPF~-RD zy!K^=Tp&ekpk&XK;LHfa+O9De*=xF{bGu@S&aCnfoM=iB+SLVmHARRTMM@jk-{f+M zAu%HFn>xGMq0?`_>4&nC+sAlTa}0AyT^5!{SM~GP+Q{^ zuZ-M_IP^?$4t53^HTaRXn;c@4h6f6f2-{}vKjgRLN)kmAjj{9l5VxbDxcbis zxrSZ?uY+1{=t+@st`x;*dmBE68N8}9Dsnq$(^qW{$A3K?fOlFHZ~-4-bwp8#vRjyyn#wqr=Ip#l*? zUnHmN;1De&Ork{X>tz}Wo=HY6=-oMFKAA~A@wu^*Iz|MjC&(JuS*?3Fl_yIH9~x(l z!s^uDik4}jY3Oo03Ec{ELDPoAqWpHNvJCMNoG+l6F6F*KUAxm65e#KvsWUDQZ)FK) z%;q4^Z`0Dtk$zf1;CzV7?0MmCm|_x}wF`;~I$F>=(8?rO@W{WVoNeMYG4bt^(m>Sx zMCA65?&#Ld0r_r^8k~+~aeWcuVxV%tl@sbFpo4`NgpO#mGL`={-rBZhiE4mmeakW- zsS(H2Ak;LknzZjaW-}+Rxv%=dVCOh;+9e)dTM}ItbDLX*35%cL*R&b?g~*;HyDv64 z#p!HRlNh`he@7{CA>q+PQB(V{rzGuPwa4k3=!7#%;Bc68Yf-CMmg%ZzD#Rl0VEqzk z`oIh|b*VtOa?Z3l^t-yM`}S&!VY6`?O!v_jW&NsL9hpw~o*MW13MR7?3`6H+9ri$x z&i{R5inx$U%mnX<&(MZ>v!U>MiH*VzqGaKQW-Iomm%G7Ho!#J1ZqMFdus4dSx5@nW zj!Q##)T~8=yN4FEKd$4_UKAdRW_eHDA|2TMtvu*il<8|7VkfpY5n1tbf_yT}ErE;g zU(4l`Fs*O1{2oI#9|NB*oMb_K-3*U8#ieDg@?2^$^-|1}srDqKS#z98>&yHu^d%#r zX}R?WR9&Y4NvHM2+C~<4B0Y}Y4=HX|tK-%xAL_%4Ec&&}77AO78AB%7 zFyzd?g)U?(Qn1hU;yAfH^51oQjNNrdHh;u8Pq^IV^P+PeMkVUiLuq~n#Au|V!`dGHN+RskHHAV-)ke8t zA^Fp?(IC8yO6-a;2j)Oox8dJ6*ACgvUOTvneb?ujDKt9=jxu{Qm|pr5yls7)QgG$R z_{Rm&YkjQFJ6I2H=xFv+e6L!SYMCXzHPgW^He9=A)2Nl|K=IutHw~+gjQS0Sq}N9~#Bkx%WylV!|^@WP|K- zKCmXP)zxil1lA~Dz8=dKYM7FnkG6jnk+2ez_YDUb@YRsG~mHf5&h&vC{+2yX`oUIAqrQTX@m{8IN? zjvP|jB23tAZh^R!u?Pu*y)B8%AUo#L?RL2e@dMt8ZV8 zG07oD>PYf~&vk|kY>Oq^4ah2oWj<*X^Qh}gX1dsIKikqcl;&ZnW6!Q^@Z5hzf*^?= zGHo^zKGd0Vlx|I17%}suP2}IIDBk86J}ppQHxs+>U4>sfA8bh$(jbB5S9F|B+b61s zTXuYG&qu>}-C^ll)CRM6nX}Khlrj0;z?Nk5O)N6qXTfW%1-8RH3GY4zw)a z`7M6JXQgc!Hnc;(n@4VfYoOh$V=sUc<|s_|g0DmnTi95T3DY_`yEHiC>v-YYRnQQ-4UsH3=VPsWbm zJD)__2$nM=K7VnIEZN+17F_Y9&>=M8QOyQ-*3=c1(H|POrYcZ!9EUanUIzDD+igE! z{(q;b@8xxx+;^j+iDt5K!n38zo*L>2WBG33K#}9b%`c5Q^ zQy+C=M*#PKJU4Q1`hIqEVH3erMmJhp#Uf*fxJ8DIi=>OxLZ#gh=10ZAQpPT=Zy%#1 z${$+&7u^|LwQkUGfPV?c{V=|_Yrq+v+hW<8;lD>F8K}zBTXM3N;ehb^c(8aonCHHcPxG_SSNsw|MU5o zWm-x+V^6$nE2waSZ5y9cnkpN)-M(eqs5333AVFU1n^`RYwLhpU5Tv9~H!>E3MmSC= ztP5($C`_(2SJe|qqsn%cb-YBjqLCcSB!b>@t)(33+3uZ{`c)8WVvJ=%7GDvfFz{h| ztnN_uiEQP$dBj(FsDC&X1JuYbjPB;3=KO)^kV1!h=_DA5l3oo4Cpw0}VTBX-8^LaI zO8TcFR2@IH@TtWPy<`k-|Ky!(m8!VPSv2Lcu{N zm6dHe@P;KDKBnbWN0U}G17Do58*!axoDuRH^r@b8SM*_m<~IvnNPf5R6vjbtOT%uz z`3B`8G3e}sIaj}!|6?$i5PQsDI>$stCj@2`bB26XSQQd26W0HZPCqvj-lH#da!q=; zjkF_{Zf&3BGCgG*EswDqfOiC6#D(TF{%V)dCqLNT_Td~89){JsCO&}mQle;AwOz0L zGir5sJNU2W(`OofWMnALS%#D-=X$V3VT&iEKc>-ucegC6P7Plmitc`LB8xS)_M~E% z-La4}9tOC1WYo^ zx<;$%>R=GQU@V1Ce;CrfI20N_ei81EolQ(9*1V#KHp5l~*81%|SpgIzfF~MLj4et3 z=3Z`((T)CO+q>i|$++jt)!yk6pj;#o?`p5w#Lme=jE^T+;&+5vP8$FQKyFILJ6vMgm6_2 z5+266oVl6{rr{s5MyIjtNo=F}MJkllF-(S?Pr@lT3DieJ|UGfLj0ZwY!C~ zyS3UA{zj&6U*^sezGg_Z7M()6zU-PX+FL-vW31k=+!#HJHj7U5CPf9sd1H-!99GJ^ z@^av6@&HDMiDYN7Jd&AYoh~VJ{U_xSzNDsG%2z|OGy|%2!EjX`lPg5g<;GAo{@-DL zNg)r<@|cr1LV62bDPKA}OFK$;3_0%{8B1i=GfEB`Rc2r3uKAu_a#a!=?-W@2-xTN0 zcU?)??jF@m%0bY}uAbA_F}VL#5-5~ur`QK_a_uw7gyR2_J5&|-mTQTu6HL!ILP)|c zmpD`-{JmW+C(q;d1f*ZKjug|-?SK@+-CG;4mUhE{!&S#I6h>|c2e$bW8rc?61wAj? z)nZCu`1npib^mbP)K|6V5;ZiMaQZ0_y4{RGYlLN5YtvirDZ0_&mm2(z_}XTbqWCA~ zq?Hf9)US(DOS6%-^tnR&`8ExHDdLumAlt?`F{2EZnZI8AlNNb|49zSbV`rssV0X~d=m_O#v7;H;BQ_0YM(eR>dtrn5W60whOMNxftF;0irdPD|d+$*tAG)Yt zt(ilxkbJ#=ewqmr**@$2!=9rN_z=kD5yitYH6z{Mql}Ez3{)$;J+7R%eMQ8SEko5V z!vlK?GsVN?Jk8P!go~l|8r=)Bd_*B%(`=CU{zqB2sZp7bR?&P!b|g|8i-|B}G7SsMOU-s{%@Kq| zxb+W=M^oCwtJ#a-kzQ>s=cPj}*h4aJVysie&h!LB2GAK!%=njh5LS!mj$``Hh<{SH-(`uwpTw@ zzA5Gov`BLlI?)z`BkQ_XWgQ}RQ`L;{m;^Lr4WN|N&rfK4BpDD$4ym0SY7~`Kk{TZC zJeQOKjFL*9W5Y7Y0QHuemm@!hTX~4|-`BvUc=4c7L6e>`as-&-Tg6w8LY(D9wMpkj z1ZW}KEf%3?Q_iu*Ka*gW5q9j4#F`hHWF~j(I9s~ZGAse> zSM%=q88(BL0{MtiemhANh(c$+N6)j`_=v0DC={RbgEqpc7s7)j8XzPGc2g&Xh%r!qzN{i z12$Za#)Oy^iz#F$t09PLYpn)*a!kS+VKd}^O*vUxcT3OV%)ZfEO0^f?X1-QS{kxKg+GrfYsQ$zdOv?@U|#SFFPT-;dzraI06a6revk=To-?dvl;nMmzhXRe4tuNhw@xU2Y)j~e@~7Q2_TZO zt95$Xq&d$zKl&0#XuX4JDP>L!GSsBT^5j-S$ZVRwY_eu+D&>kl@M5243HtNZ3XGWG z`6H4wQOLOJBn(0OdMa#R5({?u*nJl{VOTP@`(HlZ^+TaB@wQhNDis_}SziT<289so zvrY5<3)p;mT^AR~9~BjG>x+)q9d}y}HhpHyfCLDq`&9lEC&2mf>>Q*ht0q$=_4&tt E1IoRQH2?qr diff --git a/src/app/new-post/page.tsx b/src/app/new-post/page.tsx index 7fe89b4..2f699e7 100644 --- a/src/app/new-post/page.tsx +++ b/src/app/new-post/page.tsx @@ -4,7 +4,7 @@ import useAxios from "@/hooks/useAxios"; import { optimizeImageToWebP, optimizeVideoToMp4 } from "@/lib/media"; -import { createStoryBase64, StoryTextOverlay } from "@/api/fetchStories"; +import { createStoryBase64, StoryOverlay } from "@/api/fetchStories"; import StoryEditor from "@/components/stories/StoryEditor"; import TagUsersPicker, { TaggedUser } from "@/components/posts/TagUsersPicker"; import PostLinkPicker from "@/components/posts/PostLinkPicker"; @@ -34,12 +34,13 @@ import { } from "@/lib/postLocationNotice"; import { buildStorageUrl } from "@/components/main/BaseUrl"; import { fetchPostById } from "@/api/fetchPostById"; +import SelectBox from "@/components/elements/SelectBox"; import Cookies from "js-cookie"; import { useRouter, useSearchParams } from "next/navigation"; import React, { useEffect, useMemo, useState } from "react"; import toast from "react-hot-toast"; import { useTranslation } from "react-i18next"; -import { User } from "@/types/types"; +import { ICity, IProvince, User } from "@/types/types"; type CreateMode = "image" | "video" | "story"; @@ -84,13 +85,40 @@ export default function NewPostPage() { const [selectedShopProducts, setSelectedShopProducts] = useState< SelectedPostLink[] >([]); - const [storyOverlays, setStoryOverlays] = useState([]); + const [selectedBooking, setSelectedBooking] = useState( + [] + ); + const [storyOverlays, setStoryOverlays] = useState([]); const [videoCover, setVideoCover] = useState(null); const [existingVideoPath, setExistingVideoPath] = useState(null); const [locationNoticeOpen, setLocationNoticeOpen] = useState(false); const [expertiseModalOpen, setExpertiseModalOpen] = useState(false); const [loadingEdit, setLoadingEdit] = useState(false); + // شهر/استان اختیاری پست — مستقل از موقعیت پروفایل کاربر، مثل بیلبورد/پروژه + const [provinces, setProvinces] = useState(null); + const [cities, setCities] = useState(null); + const [provinceId, setProvinceId] = useState(""); + const [cityId, setCityId] = useState(""); + + useEffect(() => { + request<{ provinces: IProvince[] }>("GET", "/provinces") + .then((res) => setProvinces(res?.provinces || null)) + .catch(() => {}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (!provinceId) { + setCities(null); + return; + } + request<{ cities: ICity[] }>("GET", `/cities/${provinceId}`) + .then((res) => setCities(res?.cities || [])) + .catch(() => {}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [provinceId]); + const modeLabels: Record = useMemo( () => ({ image: t("posts.modeImage"), @@ -310,7 +338,8 @@ export default function NewPostPage() { selectedBillboards, captionLang, selectedShops, - selectedShopProducts + selectedShopProducts, + selectedBooking ); if (caption.length > POST_CAPTION_MAX_LENGTH) { @@ -442,6 +471,9 @@ export default function NewPostPage() { linked_billboard_id: selectedBillboards[0]?._id ?? null, linked_shop_id: selectedShops[0]?._id ?? null, linked_shop_product_id: selectedShopProducts[0]?._id ?? null, + linked_booking_id: selectedBooking[0]?._id ?? null, + province_id: provinceId || null, + city_id: cityId || null, }, { noToast: true }); toast.success(t("posts.postPublished"), { id: "post-upload" }); router.push("/"); @@ -494,7 +526,8 @@ export default function NewPostPage() { selectedBillboards, captionLang, selectedShops, - selectedShopProducts + selectedShopProducts, + selectedBooking ); const isStory = mode === "story"; @@ -674,12 +707,43 @@ export default function NewPostPage() { selectedBillboards={selectedBillboards} selectedShops={selectedShops} selectedShopProducts={selectedShopProducts} + selectedBooking={selectedBooking} onPackagesChange={setSelectedPackages} onProjectsChange={setSelectedProjects} onBillboardsChange={setSelectedBillboards} onShopsChange={setSelectedShops} onShopProductsChange={setSelectedShopProducts} + onBookingChange={setSelectedBooking} /> + +
+ { + setProvinceId(e.target.value); + setCityId(""); + }} + > + + {provinces?.map((item) => ( + + ))} + + setCityId(e.target.value)} + disabled={!provinceId} + > + + {cities?.map((item) => ( + + ))} + +
)} diff --git a/src/app/offer/[id]/page.tsx b/src/app/offer/[id]/page.tsx index 45371e2..84d6055 100644 --- a/src/app/offer/[id]/page.tsx +++ b/src/app/offer/[id]/page.tsx @@ -202,7 +202,8 @@ function TicketChat({ params }: ITicketChatProps) {
@@ -101,7 +101,7 @@ function BookingNamePage() { )} - + -
+
{t("booking.previewTitle")} @@ -109,6 +110,11 @@ function BookingPreviewPage() { {t("booking.holidaysTitle")}: {config.holidayDates.join("، ")}

)} + {config.weeklyRepeatCount ? ( +

+ {t("booking.weeklyRepeatCountTitle")}: {config.weeklyRepeatCount} +

+ ) : null}

{t("booking.depositTitle")}:{" "} {config.depositRequired ? t("common.yes") : t("common.no")} @@ -117,7 +123,7 @@ function BookingPreviewPage() {

)} - + ([]); const [newHoliday, setNewHoliday] = useState(""); - const [depositRequired, setDepositRequired] = useState(false); + const [depositRequired, setDepositRequired] = useState(true); + const [weeklyRepeatCount, setWeeklyRepeatCount] = useState(""); useEffect(() => { if (!configId) return; @@ -48,6 +49,7 @@ function BookingSchedulePage() { weeklySchedule?: WeeklyScheduleEntry[]; holidayDates?: string[]; depositRequired?: boolean; + weeklyRepeatCount?: number | null; }; }>("GET", `/bookings/${configId}`).then((res) => { const config = res?.config; @@ -67,7 +69,10 @@ function BookingSchedulePage() { config.holidayDates.map((d) => new Date(d).toISOString().slice(0, 10)) ); } - if (config.depositRequired) setDepositRequired(true); + setDepositRequired(Boolean(config.depositRequired)); + setWeeklyRepeatCount( + config.weeklyRepeatCount ? String(config.weeklyRepeatCount) : "" + ); }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [configId]); @@ -130,11 +135,18 @@ function BookingSchedulePage() { return; } + const trimmedRepeatCount = weeklyRepeatCount.trim(); + if (trimmedRepeatCount && (!/^\d+$/.test(trimmedRepeatCount) || Number(trimmedRepeatCount) < 1)) { + toast.error(t("booking.weeklyRepeatCountInvalid")); + return; + } + try { await request("PATCH", `/bookings/${configId}/schedule`, { weeklySchedule, holidayDates, depositRequired, + weeklyRepeatCount: trimmedRepeatCount ? Number(trimmedRepeatCount) : null, }); router.push("/settings/booking/new/preview"); } catch (err: unknown) { @@ -148,7 +160,7 @@ function BookingSchedulePage() { return ( -
+
{t("booking.scheduleTitle")} @@ -206,6 +218,22 @@ function BookingSchedulePage() { ))}
+
+ {t("booking.weeklyRepeatCountTitle")} +

+ {t("booking.weeklyRepeatCountHint")} +

+ setWeeklyRepeatCount(e.target.value)} + placeholder={t("booking.weeklyRepeatCountPlaceholder")} + className="mt-2 w-24 rounded-xl border border-neutral-300 bg-white px-3 py-2 text-sm dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-50" + /> +
+
{t("booking.holidaysTitle")} @@ -260,7 +288,7 @@ function BookingSchedulePage() {

)} - + (null); const [selectedIds, setSelectedIds] = useState>(new Set()); + const [isAddModalOpen, setAddModalOpen] = useState(false); + const [adding, setAdding] = useState(false); - useEffect(() => { + const fetchServices = () => request<{ user: User }>("GET", "/profile?services=1").then((res) => { setServices(res?.user?.services || []); }); + + useEffect(() => { + fetchServices(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -53,6 +60,54 @@ function BookingServicesPage() { }); }; + const handleAddService = async (newService: Service) => { + if (!services) return; + setAdding(true); + const previousIds = new Set( + services.map((s) => s.id || s._id || "").filter(Boolean) + ); + const nextServices = [...services, newService]; + + try { + const formData = new FormData(); + formData.append("services", JSON.stringify(nextServices)); + nextServices.forEach((service) => { + if (!service.image) return; + if (service.image.startsWith("/services/")) { + formData.append(`existingServiceImages[${service.id}]`, service.image); + } else { + const blob = dataURLtoBlob(service.image); + formData.append(`serviceImages[${service.id}]`, blob, `service-${service.id}.jpg`); + } + }); + + await request("POST", "/verify/services", formData, { + headers: { Accept: "application/json", "Content-Type": "multipart/form-data" }, + }); + + const res = await request<{ user: User }>("GET", "/profile?services=1"); + const refreshed = res?.user?.services || []; + setServices(refreshed); + setAddModalOpen(false); + + const addedService = refreshed.find( + (s) => !previousIds.has(s.id || s._id || "") + ); + if (addedService) { + const addedId = addedService.id || addedService._id || ""; + if (addedId) toggle(addedId); + } + toast.success(t("settings.edit.save")); + } catch (err: unknown) { + const message = + (err as { response?: { data?: { message?: string } } })?.response + ?.data?.message || t("shops.unknownError"); + toast.error(message); + } finally { + setAdding(false); + } + }; + const handleSubmit = async () => { if (!configId || selectedIds.size === 0) return; try { @@ -71,11 +126,20 @@ function BookingServicesPage() { return ( -
+
- - {t("booking.servicesTitle")} - +
+ + {t("booking.servicesTitle")} + + +
{services === null ? (

@@ -97,19 +161,23 @@ function BookingServicesPage() { const id = service.id || service._id || ""; const selected = selectedIds.has(id); return ( - +

); })}
)} - +
+ {isAddModalOpen && ( + !adding && setAddModalOpen(false)} + onAdd={handleAddService} + /> + )} ); diff --git a/src/app/settings/booking/reservations/page.tsx b/src/app/settings/booking/reservations/page.tsx index f8d2ada..6d0e22a 100644 --- a/src/app/settings/booking/reservations/page.tsx +++ b/src/app/settings/booking/reservations/page.tsx @@ -17,6 +17,7 @@ type BookingBuyer = { profile_image?: string; user_level?: string; is_verified?: string; + verify_badge?: string; }; type ReceivedBooking = { @@ -87,7 +88,8 @@ function BookingReservationsPage() { first_name={booking.buyer?.first_name} last_name={booking.buyer?.last_name} user_name={booking.buyer?.user_name} - is_verified={booking.buyer?.is_verified} + is_verified={booking.buyer?.verify_badge} + userId={booking.buyer?._id} />
{item.user_name} - +
{(item.first_name || item.last_name) && (

diff --git a/src/app/settings/chats/page.tsx b/src/app/settings/chats/page.tsx index d2c8c07..dc1b60a 100644 --- a/src/app/settings/chats/page.tsx +++ b/src/app/settings/chats/page.tsx @@ -6,7 +6,7 @@ import ProfileAvatar from "@/components/main/ProfileAvatar"; import VerificationBadge from "@/components/main/VerificationBadge"; import PageTitle from "@/components/settings/PageTitle"; import UserDetails from "@/components/settings/UserDetails"; -import StoryRing from "@/components/stories/StoryRing"; +import StoryRing, { verifyBadgeToTierColor } from "@/components/stories/StoryRing"; import useInfiniteScroll from "@/hooks/useInfiniteScroll"; import { useUser } from "@/hooks/useUser"; import Link from "next/link"; @@ -30,6 +30,7 @@ export interface IMessage { last_name: string; user_name: string; is_verified: string; + verify_badge?: string; profile_image?: string; last_online?: string; _id: string; @@ -236,6 +237,7 @@ function Chats() { {item.user_name} - +

diff --git a/src/app/settings/chats/rooms/[roomId]/page.tsx b/src/app/settings/chats/rooms/[roomId]/page.tsx index 46c3cbe..d71e7b2 100644 --- a/src/app/settings/chats/rooms/[roomId]/page.tsx +++ b/src/app/settings/chats/rooms/[roomId]/page.tsx @@ -54,6 +54,7 @@ type RoomMember = { last_name?: string; profile_image?: string; is_verified?: string; + verify_badge?: string; }; type RoomMessage = { @@ -186,7 +187,7 @@ function RoomMessageRow({ className="h-5 w-5 shrink-0" /> {senderName} - + ) : null} {msg.replyTo ? ( diff --git a/src/app/settings/chats/shop/[shopId]/[buyerId]/page.tsx b/src/app/settings/chats/shop/[shopId]/[buyerId]/page.tsx index a1b45c9..cbe6a5c 100644 --- a/src/app/settings/chats/shop/[shopId]/[buyerId]/page.tsx +++ b/src/app/settings/chats/shop/[shopId]/[buyerId]/page.tsx @@ -6,7 +6,7 @@ import Container from "@/components/elements/Container"; import ProfileAvatar from "@/components/main/ProfileAvatar"; import LocalePageShell from "@/components/i18n/LocalePageShell"; import ChatBoldIcon from "@/components/chat/ChatBoldIcon"; -import { chatHeaderCircleBtn, chatHeaderInfoPill } from "@/components/chat/ChatHeader"; +import { chatHeaderCircleBtn, chatHeaderInfoPill, chatHeaderGlassStyle } from "@/components/chat/ChatHeader"; import VideoMessageBubble from "@/components/chat/VideoMessageBubble"; import IOSSpinner from "@/components/ui/IOSSpinner"; import useAxios from "@/hooks/useAxios"; @@ -153,12 +153,13 @@ export default function ShopChatPage() { type="button" onClick={() => router.back()} className={chatHeaderCircleBtn} + style={chatHeaderGlassStyle} aria-label={t("chats.actions.back")} > -
+
{counterpart?.name} @@ -273,6 +274,7 @@ export default function ShopChatPage() { disabled={sending} onClick={() => attachmentInputRef.current?.click()} className={cn(chatHeaderCircleBtn, "gentle-transition disabled:opacity-40")} + style={chatHeaderGlassStyle} aria-label={t("chats.aria.attach")} > @@ -299,6 +301,7 @@ export default function ShopChatPage() { disabled={!text.trim() || sending} onClick={() => void handleSend()} className={cn(chatHeaderCircleBtn, "gentle-transition active:scale-90 disabled:opacity-40")} + style={chatHeaderGlassStyle} aria-label={t("chats.aria.send")} > diff --git a/src/app/settings/edit/License/page.tsx b/src/app/settings/edit/License/page.tsx index 77305dc..2e26b55 100644 --- a/src/app/settings/edit/License/page.tsx +++ b/src/app/settings/edit/License/page.tsx @@ -191,6 +191,8 @@ function LicensePage() { rounded="2xl" className="h-[130px] w-[130px]" fallback="/images/placeholder.png" + userId={user?._id} + verifyBadge={user?.verify_badge} />
{formatFullName(user?.first_name, user?.last_name)} diff --git a/src/app/settings/profile/user-settings/page.tsx b/src/app/settings/profile/user-settings/page.tsx index 2274552..fc3b54e 100644 --- a/src/app/settings/profile/user-settings/page.tsx +++ b/src/app/settings/profile/user-settings/page.tsx @@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react"; import Container from "@/components/elements/Container"; import PageTitle from "@/components/settings/PageTitle"; import LanguageSettingRow from "@/components/settings/LanguageSettingRow"; +import AccountAnalyticsWidget from "@/components/settings/AccountAnalyticsWidget"; import LocalePageShell from "@/components/i18n/LocalePageShell"; import useAxios from "@/hooks/useAxios"; import Link from "next/link"; @@ -157,6 +158,8 @@ export default function UserSettingsPage() {
)} + +
+ + {t("settings.nav.booking")} + + +