From 457c47bd32e6c8bdc19f27b0440183dc94a77288 Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Wed, 1 May 2024 13:13:47 +0530 Subject: [PATCH 1/8] UI: Do not show again interactive UI frontend with checkbox in modal --- src/ui/app/influencer/profile/[id]/page.tsx | 266 ++++++++++++-------- src/ui/src/utils/consts.ts | 12 +- 2 files changed, 178 insertions(+), 100 deletions(-) diff --git a/src/ui/app/influencer/profile/[id]/page.tsx b/src/ui/app/influencer/profile/[id]/page.tsx index bdd90442..ed4c34b5 100644 --- a/src/ui/app/influencer/profile/[id]/page.tsx +++ b/src/ui/app/influencer/profile/[id]/page.tsx @@ -17,6 +17,7 @@ import { EMAIL_PRIVACY_TEXT, ROLE_NAME, TWITTER_PROMOTION_TEXT, + USER_MASTER_KEY, XFLUENCER_PROMOTION_TEXT, } from "@/src/utils/consts"; import EditIcon from "@mui/icons-material/Edit"; @@ -37,6 +38,7 @@ import { TextField, Tooltip, Typography, + Checkbox, } from "@mui/material"; import dayjs from "dayjs"; import Image from "next/image"; @@ -110,85 +112,136 @@ const ProfileLayout = ({ // From the BE or anything, fetch if the user is visiting the page for the first time. const [stepIndex, setStepIndex] = React.useState(0); const [run, setRun] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Take a Quick Tour! - - - This tour will walk you through the listing of your service and - claiming your payments upon completion and validation of orders. - Simply create and list your service for business owners and let the - magic happen. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Connect a Wallet - - - Connect your wallet (if not already) before listing a service to - recieve payouts. - - - ), - target: ".joyride-wallet-table", - placement: "right", - }, - { - content: ( - - - Click on "Create A Service" - - - Please list the type of service you wish to publish, select its - price and fill in some details. Simply enter the information, and - you're all set to go. - - - ), - target: ".joyride-create-service-tab", - placement: "right", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your services tour, you're good to go and list a - service and start earning. - - - ), - placement: "center", - target: "body", - }, - ]); + const [doNotShowAgain, setDoNotShowAgain] = React.useState(false); + const [steps, setSteps] = useState([]); + const [totalServices, setTotalServices] = React.useState(0); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: "INFLUENCER_PROFILE", + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Setting the state again and again so that the value of doNotShowAgain should be the updated one. + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Take a Quick Tour! + + + This tour will walk you through the listing of your service and + claiming your payments upon completion and validation of orders. + Simply create and list your service for business owners and let + the magic happen. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Connect a Wallet + + + Connect your wallet (if not already) before listing a service to + recieve payouts. + + + ), + target: ".joyride-wallet-table", + placement: "right", + }, + { + content: ( + + + Click on "Create A Service" + + + Please list the type of service you wish to publish, select its + price and fill in some details. Simply enter the information, and + you're all set to go. + + + ), + target: ".joyride-create-service-tab", + placement: "right", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your services tour, you're good to go and list a + service and start earning. + + {!totalServices ? ( + + + + Don't show this again. + + + ) : null} + + ), + placement: "center", + target: "body", + }, + ]; + + setSteps(interactiveSteps); + }, [doNotShowAgain, totalServices]); useEffect(() => { if ( @@ -200,26 +253,6 @@ const ProfileLayout = ({ } }, [currentUser?.id, loggedInUser?.id]); - useEffect(() => { - if (params.id == loggedInUser?.id) getServices(); - }, [loggedInUser?.id, params.id]); - - const getServices = async () => { - try { - const { data, isSuccess } = await getService("packages/service", { - influencer: params.id, - status: null, - }); - if (isSuccess) { - // Open the tour if there's no service - if (!data?.pagination?.total_data_count) { - setRun(true); - } - } - } finally { - } - }; - const handleJoyrideCallback = (data: any) => { const { action, index, status, type } = data; @@ -266,8 +299,26 @@ const ProfileLayout = ({ useEffect(() => { getRegions(); + getUserGuideDetail(); }, []); + const getServices = async () => { + try { + const { data, isSuccess } = await getService("packages/service", { + influencer: params.id, + status: null, + }); + if (isSuccess) { + // Open the tour if there's no service + if (!data?.pagination?.total_data_count && !doNotShowAgain) { + setRun(true); + } + setTotalServices(data?.pagination?.total_data_count); + } + } finally { + } + }; + useEffect(() => { if (currentUser?.region) { const regionOfUser = regions.find( @@ -280,6 +331,23 @@ const ProfileLayout = ({ } }, [currentUser]); + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.INFLUENCER_PROFILE, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (!data?.data?.dont_show_again && params.id == loggedInUser?.id) { + getServices(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; + const getUserDetails = async () => { const { isSuccess, message, data } = await getService( `/account/user/${params.id}/` diff --git a/src/ui/src/utils/consts.ts b/src/ui/src/utils/consts.ts index 3a07bf90..340c6083 100644 --- a/src/ui/src/utils/consts.ts +++ b/src/ui/src/utils/consts.ts @@ -108,6 +108,16 @@ export const ORDER_STATUS = { ACCEPTED: "accepted", }; +export const USER_MASTER_KEY = { + BUSINESS_CHECKOUT: "BUSINESS_CHECKOUT", + BUSINESS_DASHBOARD: "BUSINESS_DASHBOARD", + BUSINESS_MESSAGE: "BUSINESS_MESSAGE", + INFLUENCER_PROFILE: "INFLUENCER_PROFILE", + INFLUENCER_ORDERS: "INFLUENCER_ORDERS", + INFLUENCER_DASHBOARD: "INFLUENCER_DASHBOARD", + INFLUENCER_MESSAGE: "INFLUENCER_MESSAGE", +}; + export const ORDER_ITEM_STATUS = { IN_PROGRESS: "in_progress", CANCELLED: "cancelled", @@ -702,4 +712,4 @@ export const IDL: Xfluencer = { msg: "Missmatch Order Code", }, ], -}; \ No newline at end of file +}; From 55f0b39d3c9e2cb1f768b646eaa19bbb59cc9236 Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Wed, 1 May 2024 13:14:48 +0530 Subject: [PATCH 2/8] API: Adding userGuide and userGuideMaster modal with API endpoints to fetch and update guide details --- src/api/marketplace/accounts/models.py | 58 +++++++++++++++++++- src/api/marketplace/accounts/urls.py | 3 +- src/api/marketplace/accounts/views.py | 76 ++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/src/api/marketplace/accounts/models.py b/src/api/marketplace/accounts/models.py index 7243dc9f..7e9d6886 100644 --- a/src/api/marketplace/accounts/models.py +++ b/src/api/marketplace/accounts/models.py @@ -93,7 +93,63 @@ class Meta: def __str__(self): return self.username - + + +class UserGuideMaster(models.Model): + GUIDE_CHOICES = (("BUSINESS_CHECKOUT", "BUSINESS_CHECKOUT"), + ("BUSINESS_DASHBOARD", "BUSINESS_DASHBOARD"), + ("BUSINESS_MESSAGE", "BUSINESS_MESSAGE"), + ("INFLUENCER_PROFILE", "INFLUENCER_PROFILE"), + ("INFLUENCER_ORDERS", "INFLUENCER_ORDERS"), + ("INFLUENCER_DASHBOARD", "INFLUENCER_DASHBOARD"), + ("INFLUENCER_MESSAGE", "INFLUENCER_MESSAGE"), + ) + id = models.UUIDField( + primary_key=True, + verbose_name="User Guide Master ID", + default=uuid.uuid4, + editable=False, + ) + name = models.CharField(max_length=255, blank=True, null=True) + + key = models.CharField( + choices=GUIDE_CHOICES, max_length=25 + ) + + class Meta: + db_table = "user_guide_master" + + def __str__(self): + return self.key + + +class UserGuide(models.Model): + id = models.UUIDField( + primary_key=True, + verbose_name="User Guide ID", + default=uuid.uuid4, + editable=False, + ) + user_account = models.ForeignKey( + User, + related_name="user_guide_user_account", + on_delete=SET_NULL, + null=True, + blank=True, + ) + user_guide_master = models.ForeignKey( + UserGuideMaster, + related_name="user_guide_master", + on_delete=SET_NULL, + null=True, + blank=True, + ) + dont_show_again = models.BooleanField(default=False, blank=True, null=True) + + class Meta: + db_table = "user_guide" + + class CategoryMaster(models.Model): CATEGORY_CHOICES = (("custom", "custom"), ("standard", "standard")) id = models.UUIDField( diff --git a/src/api/marketplace/accounts/urls.py b/src/api/marketplace/accounts/urls.py index a7404c72..7bdc83ed 100644 --- a/src/api/marketplace/accounts/urls.py +++ b/src/api/marketplace/accounts/urls.py @@ -15,6 +15,7 @@ AccountCategoryList, AccountCategoryDetail, TwitterPromotionView, + UserGuideDetail, UserList, UserDetail, BankAccountList, @@ -60,7 +61,7 @@ path("user/", UserList.as_view(), name="user-list"), path("user//", UserDetail.as_view(), name="user-detail"), - + path("user-guide/", UserGuideDetail.as_view(), name="user-guide-detail"), path("business-meta-data//", BusinessAccountMetaDataDetail.as_view(), name="business-account-meta-data-detail"), diff --git a/src/api/marketplace/accounts/views.py b/src/api/marketplace/accounts/views.py index 89e41da2..16fbd19a 100644 --- a/src/api/marketplace/accounts/views.py +++ b/src/api/marketplace/accounts/views.py @@ -38,6 +38,8 @@ User, BankAccount, Role, + UserGuide, + UserGuideMaster, Wallet, WalletNetwork, WalletNonce, @@ -616,6 +618,80 @@ def post(self, request): except Exception as e: return handleServerException(e) +class UserGuideDetail(APIView): + def get_or_create_user_guide(self, key, user_account): + try: + user_guide_master = UserGuideMaster.objects.get(key=key) + user_guide = UserGuide.objects.filter( + user_account=user_account, + user_guide_master=user_guide_master + ) + + if user_guide.exists(): + return user_guide.first() + else: + return UserGuide.objects.create( + user_account=user_account, + user_guide_master=user_guide_master, + ) + except Exception as e: + return None + + + authentication_classes = [JWTAuthentication] + def get(self, request): + try: + master_key = request.GET.get("master_key", "") + user_account = request.user_account + + user_guide = UserGuide.objects.filter( + user_guide_master__key=master_key, + user_account=user_account + ).first() + + dont_show_again = None + if user_guide: + dont_show_again = user_guide.dont_show_again + else: + dont_show_again = False + + return Response( + { + "isSuccess": True, + "data": { + "dont_show_again": dont_show_again, + }, + "message": "User Guide retrieved successfully", + }, + status=status.HTTP_200_OK, + ) + + except Exception as e: + return handleServerException(e) + + authentication_classes = [JWTAuthentication] + def post(self, request): + try: + do_not_show_again = request.data.get("do_not_show_again", None) + key = request.data.get("key", None) + user_account = request.user_account + + if key: + user_guide = self.get_or_create_user_guide(key, user_account) + user_guide.dont_show_again = do_not_show_again + user_guide.save() + + return Response( + { + "isSuccess": True, + "data": None, + "message": "User guide updated successfully.", + } + ) + + except Exception as e: + return handleServerException(e) + # Account Category API-Endpoint # List-Create-API From c7273611381c2ee40893f4966d78bd36a84d67ec Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Thu, 2 May 2024 15:07:50 +0530 Subject: [PATCH 3/8] minor: fix for modal not coming for twitter login for influencer --- src/ui/app/influencer/profile/[id]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/app/influencer/profile/[id]/page.tsx b/src/ui/app/influencer/profile/[id]/page.tsx index ed4c34b5..ec9f1bb4 100644 --- a/src/ui/app/influencer/profile/[id]/page.tsx +++ b/src/ui/app/influencer/profile/[id]/page.tsx @@ -300,7 +300,7 @@ const ProfileLayout = ({ useEffect(() => { getRegions(); getUserGuideDetail(); - }, []); + }, [loggedInUser?.id]); const getServices = async () => { try { From d8ffd90719930e316de3303500ef040d606bdc96 Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Mon, 6 May 2024 12:30:50 +0530 Subject: [PATCH 4/8] Add: Do not show again interactive UI in business dashboard. --- src/ui/app/business/checkout/page.tsx | 299 ++++++++++++-------- src/ui/app/influencer/profile/[id]/page.tsx | 2 +- 2 files changed, 189 insertions(+), 112 deletions(-) diff --git a/src/ui/app/business/checkout/page.tsx b/src/ui/app/business/checkout/page.tsx index 12cc10aa..636e6eb4 100644 --- a/src/ui/app/business/checkout/page.tsx +++ b/src/ui/app/business/checkout/page.tsx @@ -16,8 +16,12 @@ import { postService, putService, } from "@/src/services/httpServices"; -import { CHECKOUT_TEXT, ORDER_STATUS } from "@/src/utils/consts"; -import { Box, Button, Grid, Link, Typography } from "@mui/material"; +import { + CHECKOUT_TEXT, + ORDER_STATUS, + USER_MASTER_KEY, +} from "@/src/utils/consts"; +import { Box, Button, Checkbox, Grid, Link, Typography } from "@mui/material"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import NextLink from "next/link"; @@ -38,99 +42,166 @@ export default function CheckoutPage() { // User Guide const [stepIndex, setStepIndex] = useState(0); const [run, setRun] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Place your order successfully! - - - This tour will help you place your selected services order - accurately. Please ensure you follow each step without skipping any. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Fill in the details. - - - Enter the details and select the time to publish your service. - - - ), - placement: "right", - target: ".joyride-order-item-form", - }, - { - content: ( - - - Save your order. - - - Click on save to proceed with the payment. - - - ), - placement: "top", - target: ".joyride-order-save-button", - }, - { - content: ( - - - Make Payment - - - Once you've saved your order, click on "Make Offer" and pay via your - wallet. - - - ), - placement: "left", - target: ".joyride-make-payment", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your checkout tour, you're good to go and create - an order request. - - - ), - placement: "center", - target: "body", - }, - ]); + const [steps, setSteps] = useState(); + const [doNotShowAgain, setDoNotShowAgain] = useState(false); + + // New user guide + + // Setting the state again and again so that the value of doNotShowAgain should be the updated one. + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Place your order successfully! + + + This tour will help you place your selected services order + accurately. Please ensure you follow each step without skipping + any. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Fill in the details. + + + Enter the details and select the time to publish your service. + + + ), + placement: "right", + target: ".joyride-order-item-form", + }, + { + content: ( + + + Save your order. + + + Click on save to proceed with the payment. + + + ), + placement: "top", + target: ".joyride-order-save-button", + }, + { + content: ( + + + Make Payment + + + Once you've saved your order, click on "Make Offer" and pay via + your wallet. + + + ), + placement: "left", + target: ".joyride-make-payment", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your checkout tour, you're good to go and create + an order request. + + + + + Don't show this again. + + + + ), + placement: "center", + target: "body", + }, + ]; + setSteps(interactiveSteps); + }, [doNotShowAgain]); useEffect(() => { - getOrders(); - }, []); + getUserGuideDetail(); + }, [doNotShowAgain]); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: USER_MASTER_KEY.BUSINESS_CHECKOUT, + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.BUSINESS_CHECKOUT, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (data?.data?.dont_show_again == false) { + getOrders(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; const getOrders = async () => { try { @@ -381,23 +452,25 @@ export default function CheckoutPage() { router.back(); }} /> - { - setStepIndex(0); - setRun(true); - }} - > - - Take A Tour! - + {cart?.orderItems?.length !== 0 ? ( + { + setStepIndex(0); + setRun(true); + }} + > + + Take A Tour! + + ) : null} {cart?.orderItems?.length === 0 ? ( } /> - + diff --git a/src/ui/app/influencer/profile/[id]/page.tsx b/src/ui/app/influencer/profile/[id]/page.tsx index ec9f1bb4..02d4983a 100644 --- a/src/ui/app/influencer/profile/[id]/page.tsx +++ b/src/ui/app/influencer/profile/[id]/page.tsx @@ -120,7 +120,7 @@ const ProfileLayout = ({ try { const { isSuccess, message } = await postService(`account/user-guide/`, { do_not_show_again: !doNotShowAgain, - key: "INFLUENCER_PROFILE", + key: USER_MASTER_KEY.INFLUENCER_PROFILE, }); if (isSuccess) { From 37bb3c8dc45e7ec2379c4f24424a122e958f4d46 Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Mon, 6 May 2024 13:12:13 +0530 Subject: [PATCH 5/8] Add: Do not show interactive UI for business dashboard --- src/ui/app/business/checkout/page.tsx | 2 - src/ui/app/business/dashboard/page.tsx | 337 +++++++++++++++---------- 2 files changed, 204 insertions(+), 135 deletions(-) diff --git a/src/ui/app/business/checkout/page.tsx b/src/ui/app/business/checkout/page.tsx index 636e6eb4..d764db7c 100644 --- a/src/ui/app/business/checkout/page.tsx +++ b/src/ui/app/business/checkout/page.tsx @@ -45,8 +45,6 @@ export default function CheckoutPage() { const [steps, setSteps] = useState(); const [doNotShowAgain, setDoNotShowAgain] = useState(false); - // New user guide - // Setting the state again and again so that the value of doNotShowAgain should be the updated one. useEffect(() => { const interactiveSteps = [ diff --git a/src/ui/app/business/dashboard/page.tsx b/src/ui/app/business/dashboard/page.tsx index 8d5285f9..fd8ab079 100644 --- a/src/ui/app/business/dashboard/page.tsx +++ b/src/ui/app/business/dashboard/page.tsx @@ -16,7 +16,11 @@ import { notification } from "@/src/components/shared/notification"; import RouteProtection from "@/src/components/shared/routeProtection"; import StatusChip from "@/src/components/shared/statusChip"; import CancelEscrow from "@/src/components/web3Components/cancelEscrow"; -import { postService, putService } from "@/src/services/httpServices"; +import { + getService, + postService, + putService, +} from "@/src/services/httpServices"; import { DISPLAY_DATE_FORMAT, DISPLAY_DATE_TIME_FORMAT, @@ -24,6 +28,7 @@ import { ORDER_STATUS, SERVICE_MASTER_TWITTER_SERVICE_TYPE, TRANSACTION_TYPE, + USER_MASTER_KEY, } from "@/src/utils/consts"; import BarChartIcon from "@mui/icons-material/BarChart"; import CancelScheduleSendIcon from "@mui/icons-material/CancelScheduleSend"; @@ -34,6 +39,7 @@ import ScheduleSendIcon from "@mui/icons-material/ScheduleSend"; import { Box, Button, + Checkbox, CircularProgress, Grid, IconButton, @@ -139,116 +145,181 @@ export default function BusinessDashboardPage() { }); const [selectedTab, setSelectedTab] = React.useState(0); + const [doNotShowAgain, setDoNotShowAgain] = React.useState(false); + // User Guide only for the order's tab for the very first order. And if there are no orders only show the first step const [stepIndex, setStepIndex] = useState(0); const [run, setRun] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Manage your orders here! - - - This tour will help you manage your order accurately once you've - placed an order. The options would include editing your orders, - cancelling your orders, view the transactions, giving ratings and - many more. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Categorise your orders. - - - Click on the status you wanna view your orders for. - - - ), - placement: "top", - target: ".joyride-tabs", - }, - { - content: ( - - - Customized filters. - - - Advanced filters for orders based on the services, date, order ID, - and influencers. - - - ), - placement: "top", - target: ".joyride-dashboard-filters", - }, - { - content: ( - - - Take actions. - - - Hover the actions to see what it does and click to do the action. - Actions include viewing order details, editing your order, - cancelling the order and many more. - - - ), - placement: "top", - target: ".joyride-actions-column", - }, - { - content: ( - - - Give reviews. - - - Click here to give reviews to the orders. - - - ), - placement: "top", - target: ".joyride-review-column", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your dashboard tour, you're now good to go to - manage your orders and analyse them. - - - ), - placement: "center", - target: "body", - }, - ]); + const [steps, setSteps] = useState(); + + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Manage your orders here! + + + This tour will help you manage your order accurately once you've + placed an order. The options would include editing your orders, + cancelling your orders, view the transactions, giving ratings and + many more. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Categorise your orders. + + + Click on the status you wanna view your orders for. + + + ), + placement: "top", + target: ".joyride-tabs", + }, + { + content: ( + + + Customized filters. + + + Advanced filters for orders based on the services, date, order ID, + and influencers. + + + ), + placement: "top", + target: ".joyride-dashboard-filters", + }, + { + content: ( + + + Take actions. + + + Hover the actions to see what it does and click to do the action. + Actions include viewing order details, editing your order, + cancelling the order and many more. + + + ), + placement: "top", + target: ".joyride-actions-column", + }, + { + content: ( + + + Give reviews. + + + Click here to give reviews to the orders. + + + ), + placement: "top", + target: ".joyride-review-column", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your dashboard tour, you're now good to go to + manage your orders and analyse them. + + + + + Don't show this again. + + + + ), + placement: "center", + target: "body", + }, + ]; + + setSteps(interactiveSteps); + }, [doNotShowAgain]); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: USER_MASTER_KEY.BUSINESS_DASHBOARD, + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.BUSINESS_DASHBOARD, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (!data?.data?.dont_show_again) { + handleUserInteraction(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; const handleJoyrideCallback = (data: any) => { const { action, index, status, type } = data; @@ -285,14 +356,15 @@ export default function BusinessDashboardPage() { setStepIndex(0); setRun(true); } - if (data?.pagination?.total_data_count > 0) { - setHasAnOrder(true); - } } } finally { } }; + useEffect(() => { + getUserGuideDetail(); + }, [doNotShowAgain]); + const getOrders = async () => { try { setLoading(true); @@ -318,6 +390,11 @@ export default function BusinessDashboardPage() { total_data_count: data?.pagination?.total_data_count, total_page_count: data?.pagination?.total_page_count, }); + if (data?.pagination?.total_data_count > 0) { + setHasAnOrder(true); + } else { + setHasAnOrder(false); + } } else { notification(message ? message : "Something went wrong", "error"); } @@ -1268,10 +1345,6 @@ export default function BusinessDashboardPage() { }, ]; - useEffect(() => { - handleUserInteraction(); - }, []); - useEffect(() => { const delayDebounceFn = setTimeout(() => { if (selectedTab === 0) { @@ -1564,24 +1637,22 @@ export default function BusinessDashboardPage() { setOpen={setOpenVerifyModal} orderItemId={selectedOrderItemId} /> - {selectedTab == 0 ? ( - - ) : null} + Date: Mon, 6 May 2024 14:01:47 +0530 Subject: [PATCH 6/8] Add: Do not show again interactive UI for business messages --- src/ui/app/business/messages/page.tsx | 236 ++++++++++++++++---------- 1 file changed, 150 insertions(+), 86 deletions(-) diff --git a/src/ui/app/business/messages/page.tsx b/src/ui/app/business/messages/page.tsx index f4ef6bed..a93e6079 100644 --- a/src/ui/app/business/messages/page.tsx +++ b/src/ui/app/business/messages/page.tsx @@ -6,11 +6,12 @@ import OrderChatPanel from "@/src/components/messagesComponents/orderChatPanel"; import { notification } from "@/src/components/shared/notification"; import RouteProtection from "@/src/components/shared/routeProtection"; import { useAppSelector } from "@/src/hooks/useRedux"; -import { postService } from "@/src/services/httpServices"; -import { ORDER_STATUS } from "@/src/utils/consts"; +import { getService, postService } from "@/src/services/httpServices"; +import { ORDER_STATUS, USER_MASTER_KEY } from "@/src/utils/consts"; import ChatIcon from "@mui/icons-material/Chat"; import { Box, + Checkbox, CircularProgress, Grid, Pagination, @@ -59,83 +60,146 @@ export default function BusinessMessages() { const [stepIndex, setStepIndex] = useState(0); const [run, setRun] = useState(false); const [hasAMessage, setHasAMessage] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Chat with influencers. - - - This tour will guide you through the chatting room where you can - message the influencers and have a short discussion about your - order. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Customized filters. - - - Advanced filters for chats based on the services, order ID, and - status of orders. - - - ), - placement: "right", - target: ".joyride-message-filters", - }, - { - content: ( - - - Influencer's List. - - - Click on the influencer to chat with them and have a discussion - about the order. - - - ), - placement: "right", - target: ".joyride-user-chats", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your messages tour, you're good to go and chat with - your influencer. - - - ), - placement: "center", - target: "body", - }, - ]); + const [doNotShowAgain, setDoNotShowAgain] = useState(false); + const [steps, setSteps] = useState(); + + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Chat with influencers. + + + This tour will guide you through the chatting room where you can + message the influencers and have a short discussion about your + order. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Customized filters. + + + Advanced filters for chats based on the services, order ID, and + status of orders. + + + ), + placement: "right", + target: ".joyride-message-filters", + }, + { + content: ( + + + Influencer's List. + + + Click on the influencer to chat with them and have a discussion + about the order. + + + ), + placement: "right", + target: ".joyride-user-chats", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your messages tour, you're good to go and chat + with your influencer. + + + + + Don't show this again. + + + + ), + placement: "center", + target: "body", + }, + ]; + setSteps(interactiveSteps); + }, [doNotShowAgain]); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: USER_MASTER_KEY.BUSINESS_MESSAGE, + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.BUSINESS_MESSAGE, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (data?.data?.dont_show_again == false) { + handleUserInteraction(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; const handleJoyrideCallback = (data: any) => { const { action, index, status, type } = data; @@ -160,12 +224,13 @@ export default function BusinessMessages() { setStepIndex(0); setRun(true); } - if (data?.pagination?.total_data_count > 0) { - setHasAMessage(true); - } } }; + useEffect(() => { + getUserGuideDetail(); + }, [doNotShowAgain]); + const getAllChats = async () => { try { setLoading(true); @@ -184,6 +249,9 @@ export default function BusinessMessages() { total_data_count: data?.pagination?.total_data_count, total_page_count: data?.pagination?.total_page_count, }); + if (data?.pagination?.total_data_count > 0) { + setHasAMessage(true); + } } } finally { setLoading(false); @@ -219,10 +287,6 @@ export default function BusinessMessages() { return () => clearInterval(intervalId); }, [filters, pagination.current_page_number, pagination.current_page_size]); - useEffect(() => { - handleUserInteraction(); - }, []); - if (!user) { return ( Date: Mon, 6 May 2024 15:11:02 +0530 Subject: [PATCH 7/8] Add: Do not sow again for interactive UI for Influencer's Order and minor fix --- src/ui/app/business/checkout/page.tsx | 2 +- src/ui/app/business/dashboard/page.tsx | 2 +- src/ui/app/business/messages/page.tsx | 2 +- src/ui/app/influencer/orders/page.tsx | 262 +++++++++++++------- src/ui/app/influencer/profile/[id]/page.tsx | 2 +- 5 files changed, 170 insertions(+), 100 deletions(-) diff --git a/src/ui/app/business/checkout/page.tsx b/src/ui/app/business/checkout/page.tsx index d764db7c..7fb9472e 100644 --- a/src/ui/app/business/checkout/page.tsx +++ b/src/ui/app/business/checkout/page.tsx @@ -159,7 +159,7 @@ export default function CheckoutPage() { useEffect(() => { getUserGuideDetail(); - }, [doNotShowAgain]); + }, []); const handleDoNotShow = async () => { try { diff --git a/src/ui/app/business/dashboard/page.tsx b/src/ui/app/business/dashboard/page.tsx index fd8ab079..3cd70c93 100644 --- a/src/ui/app/business/dashboard/page.tsx +++ b/src/ui/app/business/dashboard/page.tsx @@ -363,7 +363,7 @@ export default function BusinessDashboardPage() { useEffect(() => { getUserGuideDetail(); - }, [doNotShowAgain]); + }, []); const getOrders = async () => { try { diff --git a/src/ui/app/business/messages/page.tsx b/src/ui/app/business/messages/page.tsx index a93e6079..17d0c698 100644 --- a/src/ui/app/business/messages/page.tsx +++ b/src/ui/app/business/messages/page.tsx @@ -229,7 +229,7 @@ export default function BusinessMessages() { useEffect(() => { getUserGuideDetail(); - }, [doNotShowAgain]); + }, []); const getAllChats = async () => { try { diff --git a/src/ui/app/influencer/orders/page.tsx b/src/ui/app/influencer/orders/page.tsx index 16ca9011..1275c603 100644 --- a/src/ui/app/influencer/orders/page.tsx +++ b/src/ui/app/influencer/orders/page.tsx @@ -2,7 +2,11 @@ import BackIcon from "@/public/svg/Back.svg"; import Star from "@/public/svg/Star.svg"; import { notification } from "@/src/components/shared/notification"; -import { postService, putService } from "@/src/services/httpServices"; +import { + getService, + postService, + putService, +} from "@/src/services/httpServices"; import { OpenInFull } from "@mui/icons-material"; import Image from "next/image"; @@ -15,6 +19,7 @@ import { Backdrop, Box, Button, + Checkbox, CircularProgress, Dialog, DialogActions, @@ -42,6 +47,7 @@ import { endCancellation, startCancellation, } from "@/src/reducers/orderCancellationSlice"; +import { USER_MASTER_KEY } from "@/src/utils/consts"; export default function Orders() { const router = useRouter(); @@ -73,97 +79,161 @@ export default function Orders() { // User Guide for the vwey first order const [stepIndex, setStepIndex] = useState(0); const [run, setRun] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Order's request dashboard. - - - This tour will guide you through the order requests where you can - view the orders and accept/decline based on your preference. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Select orders. - - - Click on the order row to view details about it on the right hand - drawer. - - - ), - placement: "right", - target: ".joyride-order-column", - }, - { - content: ( - - - View the order. - - - Please have a close look at the details of each order item including - the content, publish time and the amount it's offering. You can also - visit the business profile by clicking on the hyperlink. - - - ), - placement: "left", - target: ".joyride-order-details-drawer", - }, - { - content: ( - - - Accept/Decline Orders. - - - Accept or decline the order based on your pereference. - - - ), - placement: "left", - target: ".joyride-action-column", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your order requests tour, you're good to go and - accept or decline the order request. - - - ), - placement: "center", - target: "body", - }, - ]); + const [doNotShowAgain, setDoNotShowAgain] = useState(false); + const [steps, setSteps] = useState(); + + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Order's request dashboard. + + + This tour will guide you through the order requests where you can + view the orders and accept/decline based on your preference. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Select orders. + + + Click on the order row to view details about it on the right hand + drawer. + + + ), + placement: "right", + target: ".joyride-order-column", + }, + { + content: ( + + + View the order. + + + Please have a close look at the details of each order item + including the content, publish time and the amount it's offering. + You can also visit the business profile by clicking on the + hyperlink. + + + ), + placement: "left", + target: ".joyride-order-details-drawer", + }, + { + content: ( + + + Accept/Decline Orders. + + + Accept or decline the order based on your pereference. + + + ), + placement: "left", + target: ".joyride-action-column", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your order requests tour, you're good to go and + accept or decline the order request. + + + + + Don't show this again. + + + + ), + placement: "center", + target: "body", + }, + ]; + setSteps(interactiveSteps); + }, [doNotShowAgain]); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: USER_MASTER_KEY.INFLUENCER_ORDERS, + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.INFLUENCER_ORDERS, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (data?.data?.dont_show_again == false) { + handleUserInteraction(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; const handleJoyrideCallback = (data: any) => { const { action, index, status, type } = data; @@ -197,6 +267,10 @@ export default function Orders() { } }; + useEffect(() => { + getUserGuideDetail(); + }, []); + const getOrders = async () => { try { setLoading(true); @@ -392,10 +466,6 @@ export default function Orders() { }, ]; - useEffect(() => { - handleUserInteraction(); - }, []); - useEffect(() => { const delayDebounceFn = setTimeout(() => { getOrders(); diff --git a/src/ui/app/influencer/profile/[id]/page.tsx b/src/ui/app/influencer/profile/[id]/page.tsx index 02d4983a..96a3d33e 100644 --- a/src/ui/app/influencer/profile/[id]/page.tsx +++ b/src/ui/app/influencer/profile/[id]/page.tsx @@ -300,7 +300,7 @@ const ProfileLayout = ({ useEffect(() => { getRegions(); getUserGuideDetail(); - }, [loggedInUser?.id]); + }, []); const getServices = async () => { try { From 71a616c7145332ab8daad796a914a2cea66b99c1 Mon Sep 17 00:00:00 2001 From: Parikshit85 Date: Mon, 6 May 2024 15:59:44 +0530 Subject: [PATCH 8/8] Add: Do not show interactive UI for influencer dashboard --- src/ui/app/influencer/dashboard/page.tsx | 289 ++++++++++++++--------- 1 file changed, 177 insertions(+), 112 deletions(-) diff --git a/src/ui/app/influencer/dashboard/page.tsx b/src/ui/app/influencer/dashboard/page.tsx index bdf265f6..0e254320 100644 --- a/src/ui/app/influencer/dashboard/page.tsx +++ b/src/ui/app/influencer/dashboard/page.tsx @@ -14,7 +14,7 @@ import { notification } from "@/src/components/shared/notification"; import RouteProtection from "@/src/components/shared/routeProtection"; import StatusChip from "@/src/components/shared/statusChip"; import ClaimEscrow from "@/src/components/web3Components/claimEscrow"; -import { postService } from "@/src/services/httpServices"; +import { getService, postService } from "@/src/services/httpServices"; import { BADGES, DISPLAY_DATE_FORMAT, @@ -23,6 +23,7 @@ import { ORDER_STATUS, SERVICE_MASTER_TWITTER_SERVICE_TYPE, TRANSACTION_TYPE, + USER_MASTER_KEY, } from "@/src/utils/consts"; import CancelScheduleSendIcon from "@mui/icons-material/CancelScheduleSend"; import EditNoteIcon from "@mui/icons-material/EditNote"; @@ -32,6 +33,7 @@ import { Avatar, Badge, Box, + Checkbox, Grid, IconButton, Link, @@ -119,115 +121,178 @@ export default function BusinessDashboardPage() { const [selectedTab, setSelectedTab] = React.useState(0); // User Guide only for the order's tab for the very first order. And if there are no orders only show the first step + const [doNotShowAgain, setDoNotShowAgain] = React.useState(false); const [stepIndex, setStepIndex] = useState(0); const [run, setRun] = useState(false); - const [steps, setSteps] = useState([ - { - content: ( - - bgimg - - Manage your orders here! - - - This tour will help you manage your order accurately once you have - an order. The options would include editing the orders, claiming the - payouts, view your ratings, and many more. - - - ), - placement: "center", - target: "body", - }, - { - content: ( - - - Categorise your orders. - - - Click on the status you wanna view your orders for. - - - ), - placement: "top", - target: ".joyride-tabs", - }, - { - content: ( - - - Customized filters. - - - Advanced filters for orders based on the services, date, order ID, - and businesses. - - - ), - placement: "top", - target: ".joyride-dashboard-filters", - }, - { - content: ( - - - Take actions. - - - Hover the actions to see what it does and click to do the action. - Actions include claiming funds, viewing order details and editing - them. - - - ), - placement: "top", - target: ".joyride-actions-column", - }, - { - content: ( - - - Review by businesses. - - - Click the stars (if there's any) to see what the businesses have to - say about your work. - - - ), - placement: "top", - target: ".joyride-review-column", - }, - { - content: ( - - bgimg - - Congratulations!!! - - - You've completed your dashboard tour, you're good to go to manage - your orders and analyse your performance. - - - ), - placement: "center", - target: "body", - }, - ]); + const [steps, setSteps] = useState(); + + useEffect(() => { + const interactiveSteps = [ + { + content: ( + + bgimg + + Manage your orders here! + + + This tour will help you manage your order accurately once you have + an order. The options would include editing the orders, claiming + the payouts, view your ratings, and many more. + + + ), + placement: "center", + target: "body", + }, + { + content: ( + + + Categorise your orders. + + + Click on the status you wanna view your orders for. + + + ), + placement: "top", + target: ".joyride-tabs", + }, + { + content: ( + + + Customized filters. + + + Advanced filters for orders based on the services, date, order ID, + and businesses. + + + ), + placement: "top", + target: ".joyride-dashboard-filters", + }, + { + content: ( + + + Take actions. + + + Hover the actions to see what it does and click to do the action. + Actions include claiming funds, viewing order details and editing + them. + + + ), + placement: "top", + target: ".joyride-actions-column", + }, + { + content: ( + + + Review by businesses. + + + Click the stars (if there's any) to see what the businesses have + to say about your work. + + + ), + placement: "top", + target: ".joyride-review-column", + }, + { + content: ( + + bgimg + + Congratulations!!! + + + You've completed your dashboard tour, you're good to go to manage + your orders and analyse your performance. + + + + + Don't show this again. + + + + ), + placement: "center", + target: "body", + }, + ]; + setSteps(interactiveSteps); + }, [doNotShowAgain]); + + const handleDoNotShow = async () => { + try { + const { isSuccess, message } = await postService(`account/user-guide/`, { + do_not_show_again: !doNotShowAgain, + key: USER_MASTER_KEY.INFLUENCER_DASHBOARD, + }); + + if (isSuccess) { + if (!doNotShowAgain) { + notification("User Guide won't be shown automatically!", "success"); + setRun(false); + } + setDoNotShowAgain((prevState) => !prevState); + } else { + notification( + message ? message : "Something went wrong while setting user guide", + "error" + ); + } + } finally { + } + }; + + // Get the status of do not show again checkbox for the particular user for a particular guide master key + const getUserGuideDetail = async () => { + try { + const { isSuccess, data } = await getService(`/account/user-guide`, { + master_key: USER_MASTER_KEY.INFLUENCER_DASHBOARD, + }); + if (isSuccess) { + setDoNotShowAgain(data?.data?.dont_show_again); + if (!data?.data?.dont_show_again) { + handleUserInteraction(); + } + } + } catch (error) { + console.error("Failed to get user guide details:", error); + } + }; const handleJoyrideCallback = (data: any) => { const { action, index, status, type } = data; @@ -284,6 +349,10 @@ export default function BusinessDashboardPage() { } }; + useEffect(() => { + getUserGuideDetail(); + }, []); + const getOrders = async () => { try { setLoading(true); @@ -1147,10 +1216,6 @@ export default function BusinessDashboardPage() { }, ]; - useEffect(() => { - handleUserInteraction(); - }, []); - useEffect(() => { const tab = searchParams.get("tab"); const _selectedTab = tabs.find((_tab) => _tab.key === tab);