mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-01 14:52:02 +00:00
update and unify modals into generic component
This commit is contained in:
parent
2b10e74d35
commit
5d884cf2b6
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { Tooltip } from 'primereact/tooltip';
|
import { Tooltip } from 'primereact/tooltip';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ const MoreInfo = ({
|
|||||||
/>
|
/>
|
||||||
{!isMobile && <Tooltip target=".pi-question-circle" position={tooltipPosition} />}
|
{!isMobile && <Tooltip target=".pi-question-circle" position={tooltipPosition} />}
|
||||||
|
|
||||||
<Dialog
|
<Modal
|
||||||
header={modalTitle}
|
header={modalTitle}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onHide={() => setVisible(false)}
|
onHide={() => setVisible(false)}
|
||||||
@ -32,7 +32,7 @@ const MoreInfo = ({
|
|||||||
breakpoints={{ '960px': '75vw', '641px': '90vw' }}
|
breakpoints={{ '960px': '75vw', '641px': '90vw' }}
|
||||||
>
|
>
|
||||||
{typeof modalBody === 'string' ? <p className="text-gray-200">{modalBody}</p> : modalBody}
|
{typeof modalBody === 'string' ? <p className="text-gray-200">{modalBody}</p> : modalBody}
|
||||||
</Dialog>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { LightningAddress } from '@getalby/lightning-tools';
|
import { LightningAddress } from '@getalby/lightning-tools';
|
||||||
import { track } from '@vercel/analytics';
|
import { track } from '@vercel/analytics';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -227,11 +227,11 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Dialog
|
<Modal
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
onHide={() => setDialogVisible(false)}
|
onHide={() => setDialogVisible(false)}
|
||||||
header="Make Payment"
|
header="Make Payment"
|
||||||
style={{ width: isMobile ? '90vw' : '50vw' }}
|
width={isMobile ? '90vw' : '50vw'}
|
||||||
>
|
>
|
||||||
{invoice ? (
|
{invoice ? (
|
||||||
<Payment
|
<Payment
|
||||||
@ -243,7 +243,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
|
|||||||
) : (
|
) : (
|
||||||
<p>Loading payment details...</p>
|
<p>Loading payment details...</p>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { track } from '@vercel/analytics';
|
import { track } from '@vercel/analytics';
|
||||||
import { LightningAddress } from '@getalby/lightning-tools';
|
import { LightningAddress } from '@getalby/lightning-tools';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -122,11 +122,11 @@ const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resource
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Dialog
|
<Modal
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
onHide={() => setDialogVisible(false)}
|
onHide={() => setDialogVisible(false)}
|
||||||
header="Make Payment"
|
header="Make Payment"
|
||||||
style={{ width: isMobile ? '90vw' : '50vw' }}
|
width={isMobile ? '90vw' : '50vw'}
|
||||||
>
|
>
|
||||||
{invoice ? (
|
{invoice ? (
|
||||||
<Payment
|
<Payment
|
||||||
@ -138,7 +138,7 @@ const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resource
|
|||||||
) : (
|
) : (
|
||||||
<p>Loading payment details...</p>
|
<p>Loading payment details...</p>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Dropdown } from 'primereact/dropdown';
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
import GenericButton from '@/components/buttons/GenericButton';
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { Accordion, AccordionTab } from 'primereact/accordion';
|
import { Accordion, AccordionTab } from 'primereact/accordion';
|
||||||
import EmbeddedDocumentForm from '@/components/forms/course/embedded/EmbeddedDocumentForm';
|
import EmbeddedDocumentForm from '@/components/forms/course/embedded/EmbeddedDocumentForm';
|
||||||
import EmbeddedVideoForm from '@/components/forms/course/embedded/EmbeddedVideoForm';
|
import EmbeddedVideoForm from '@/components/forms/course/embedded/EmbeddedVideoForm';
|
||||||
@ -233,23 +233,23 @@ const LessonSelector = ({
|
|||||||
</Accordion>
|
</Accordion>
|
||||||
<GenericButton label="Add New Lesson" onClick={addNewLesson} className="mt-4" type="button" />
|
<GenericButton label="Add New Lesson" onClick={addNewLesson} className="mt-4" type="button" />
|
||||||
|
|
||||||
<Dialog
|
<Modal
|
||||||
className="w-full max-w-screen-md"
|
className="w-full max-w-screen-md"
|
||||||
visible={showDocumentForm}
|
visible={showDocumentForm}
|
||||||
onHide={() => setShowDocumentForm(false)}
|
onHide={() => setShowDocumentForm(false)}
|
||||||
header="Create New Document"
|
header="Create New Document"
|
||||||
>
|
>
|
||||||
<EmbeddedDocumentForm onSave={handleNewDocumentSave} isPaid={isPaidCourse} />
|
<EmbeddedDocumentForm onSave={handleNewDocumentSave} isPaid={isPaidCourse} />
|
||||||
</Dialog>
|
</Modal>
|
||||||
|
|
||||||
<Dialog
|
<Modal
|
||||||
className="w-full max-w-screen-md"
|
className="w-full max-w-screen-md"
|
||||||
visible={showVideoForm}
|
visible={showVideoForm}
|
||||||
onHide={() => setShowVideoForm(false)}
|
onHide={() => setShowVideoForm(false)}
|
||||||
header="Create New Video"
|
header="Create New Video"
|
||||||
>
|
>
|
||||||
<EmbeddedVideoForm onSave={handleNewVideoSave} isPaid={isPaidCourse} />
|
<EmbeddedVideoForm onSave={handleNewVideoSave} isPaid={isPaidCourse} />
|
||||||
</Dialog>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
const WelcomeModal = () => {
|
const WelcomeModal = () => {
|
||||||
@ -26,10 +26,11 @@ const WelcomeModal = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Modal
|
||||||
header="Welcome to PlebDevs!"
|
header="Welcome to PlebDevs!"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
style={{ width: '90vw', maxWidth: '600px' }}
|
width="90vw"
|
||||||
|
style={{ maxWidth: '600px' }}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
>
|
>
|
||||||
<div className="text-center mb-4">
|
<div className="text-center mb-4">
|
||||||
@ -74,7 +75,7 @@ const WelcomeModal = () => {
|
|||||||
<p className="font-bold text-lg">Let's start your coding journey! 🚀</p>
|
<p className="font-bold text-lg">Let's start your coding journey! 🚀</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
@ -99,7 +99,13 @@ const UserBadges = ({ visible, onHide }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog header="Your Badges" visible={visible} onHide={onHide} className="w-full max-w-3xl">
|
<Modal
|
||||||
|
header="Your Badges"
|
||||||
|
visible={visible}
|
||||||
|
onHide={onHide}
|
||||||
|
width="full"
|
||||||
|
className="max-w-3xl"
|
||||||
|
>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex justify-center items-center h-40">
|
<div className="flex justify-center items-center h-40">
|
||||||
@ -147,7 +153,7 @@ const UserBadges = ({ visible, onHide }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Menu } from 'primereact/menu';
|
import { Menu } from 'primereact/menu';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
import { useImageProxy } from '@/hooks/useImageProxy';
|
import { useImageProxy } from '@/hooks/useImageProxy';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -284,12 +284,12 @@ const UserProfileCard = ({ user }) => {
|
|||||||
<>
|
<>
|
||||||
{windowWidth <= 1440 ? <MobileProfileCard /> : <DesktopProfileCard />}
|
{windowWidth <= 1440 ? <MobileProfileCard /> : <DesktopProfileCard />}
|
||||||
<UserBadges visible={showBadges} onHide={() => setShowBadges(false)} />
|
<UserBadges visible={showBadges} onHide={() => setShowBadges(false)} />
|
||||||
<Dialog
|
<Modal
|
||||||
visible={showRelaysModal}
|
visible={showRelaysModal}
|
||||||
onHide={() => setShowRelaysModal(false)}
|
onHide={() => setShowRelaysModal(false)}
|
||||||
header="Manage Relays"
|
header="Manage Relays"
|
||||||
className="w-[90vw] max-w-[800px]"
|
width="full"
|
||||||
modal
|
className="max-w-[800px]"
|
||||||
>
|
>
|
||||||
<UserRelaysTable
|
<UserRelaysTable
|
||||||
ndk={ndk}
|
ndk={ndk}
|
||||||
@ -297,7 +297,7 @@ const UserProfileCard = ({ user }) => {
|
|||||||
setUserRelays={setUserRelays}
|
setUserRelays={setUserRelays}
|
||||||
reInitializeNDK={reInitializeNDK}
|
reInitializeNDK={reInitializeNDK}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
@ -25,10 +25,10 @@ const CalendlyEmbed = ({ visible, onHide, userId, userEmail, userName }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Modal
|
||||||
header="Schedule a Meeting"
|
header="Schedule a Meeting"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
style={{ width: windowWidth < 768 ? '100vw' : '50vw' }}
|
width={windowWidth < 768 ? '100vw' : '50vw'}
|
||||||
footer={dialogFooter}
|
footer={dialogFooter}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
>
|
>
|
||||||
@ -37,7 +37,7 @@ const CalendlyEmbed = ({ visible, onHide, userId, userEmail, userName }) => {
|
|||||||
data-url={`https://calendly.com/plebdevs/30min?hide_event_type_details=1&hide_gdpr_banner=1&email=${encodeURIComponent(userEmail)}&name=${encodeURIComponent(userName)}&custom_data=${encodeURIComponent(JSON.stringify({ user_id: userId }))}`}
|
data-url={`https://calendly.com/plebdevs/30min?hide_event_type_details=1&hide_gdpr_banner=1&email=${encodeURIComponent(userEmail)}&name=${encodeURIComponent(userName)}&custom_data=${encodeURIComponent(JSON.stringify({ user_id: userId }))}`}
|
||||||
style={{ minWidth: '320px', height: '700px' }}
|
style={{ minWidth: '320px', height: '700px' }}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -31,7 +31,11 @@ const CancelSubscription = ({ visible, onHide }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog header="Cancel Subscription" visible={visible} onHide={onHide}>
|
<Modal
|
||||||
|
header="Cancel Subscription"
|
||||||
|
visible={visible}
|
||||||
|
onHide={onHide}
|
||||||
|
>
|
||||||
<p>Are you sure you want to cancel your subscription?</p>
|
<p>Are you sure you want to cancel your subscription?</p>
|
||||||
<div className="flex flex-row justify-center mt-6">
|
<div className="flex flex-row justify-center mt-6">
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
@ -46,7 +50,7 @@ const CancelSubscription = ({ visible, onHide }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -111,11 +111,11 @@ const LightningAddressForm = ({ visible, onHide }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Modal
|
||||||
header="Lightning Address"
|
header="Lightning Address"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
style={{ width: windowWidth < 768 ? '100vw' : '60vw' }}
|
width={windowWidth < 768 ? '100vw' : '60vw'}
|
||||||
>
|
>
|
||||||
{existingLightningAddress ? (
|
{existingLightningAddress ? (
|
||||||
<p>Update your Lightning Address details</p>
|
<p>Update your Lightning Address details</p>
|
||||||
@ -216,7 +216,7 @@ const LightningAddressForm = ({ visible, onHide }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
@ -82,11 +82,11 @@ const Nip05Form = ({ visible, onHide }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Modal
|
||||||
header="NIP-05"
|
header="NIP-05"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
style={{ width: windowWidth < 768 ? '100vw' : '60vw' }}
|
width={windowWidth < 768 ? '100vw' : '60vw'}
|
||||||
>
|
>
|
||||||
{existingNip05 ? <p>Update your Pubkey and Name</p> : <p>Confirm your Pubkey and Name</p>}
|
{existingNip05 ? <p>Update your Pubkey and Name</p> : <p>Confirm your Pubkey and Name</p>}
|
||||||
<div className="flex flex-col gap-2 max-mob:min-w-[80vw] max-tab:min-w-[60vw] min-w-[40vw]">
|
<div className="flex flex-col gap-2 max-mob:min-w-[80vw] max-tab:min-w-[60vw] min-w-[40vw]">
|
||||||
@ -126,7 +126,7 @@ const Nip05Form = ({ visible, onHide }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { Card } from 'primereact/card';
|
import { Card } from 'primereact/card';
|
||||||
import { ProgressSpinner } from 'primereact/progressspinner';
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton';
|
import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton';
|
||||||
@ -50,11 +50,10 @@ const RenewSubscription = ({ visible, onHide, subscribedUntil }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Modal
|
||||||
header="Renew Your PlebDevs Subscription"
|
header="Renew Your PlebDevs Subscription"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
className="p-fluid pb-0 w-fit"
|
|
||||||
>
|
>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
@ -81,7 +80,7 @@ const RenewSubscription = ({ visible, onHide, subscribedUntil }) => {
|
|||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import Modal from '@/components/ui/Modal';
|
||||||
import { ProgressSpinner } from 'primereact/progressspinner';
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton';
|
import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
@ -216,11 +216,10 @@ const SubscribeModal = ({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
<Dialog
|
<Modal
|
||||||
header="Subscribe to PlebDevs"
|
header="Subscribe to PlebDevs"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
className="p-fluid pb-0 w-fit"
|
|
||||||
>
|
>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
@ -230,7 +229,7 @@ const SubscribeModal = ({ user }) => {
|
|||||||
<span className="ml-2">Processing subscription...</span>
|
<span className="ml-2">Processing subscription...</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Card className="shadow-lg">
|
<Card className="shadow-none">
|
||||||
<div className="text-center mb-6">
|
<div className="text-center mb-6">
|
||||||
<h2 className="text-2xl font-bold text-primary mb-2">Unlock Premium Benefits</h2>
|
<h2 className="text-2xl font-bold text-primary mb-2">Unlock Premium Benefits</h2>
|
||||||
<p className="text-gray-400">Subscribe now and elevate your development journey!</p>
|
<p className="text-gray-400">Subscribe now and elevate your development journey!</p>
|
||||||
@ -295,7 +294,7 @@ const SubscribeModal = ({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Modal>
|
||||||
<CalendlyEmbed
|
<CalendlyEmbed
|
||||||
visible={calendlyVisible}
|
visible={calendlyVisible}
|
||||||
onHide={() => setCalendlyVisible(false)}
|
onHide={() => setCalendlyVisible(false)}
|
||||||
|
112
src/components/ui/Modal.js
Normal file
112
src/components/ui/Modal.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic modal component based on PrimeReact Dialog with dark styling
|
||||||
|
* @param {Object} props - Component props
|
||||||
|
* @param {string} props.header - Modal header text
|
||||||
|
* @param {boolean} props.visible - Whether the modal is visible
|
||||||
|
* @param {Function} props.onHide - Function to call when modal is closed
|
||||||
|
* @param {React.ReactNode} props.children - Modal content
|
||||||
|
* @param {string} props.className - Additional CSS classes for the modal
|
||||||
|
* @param {Object} props.style - Additional inline styles for the modal
|
||||||
|
* @param {string} props.width - Width of the modal (fit, full, or pixel value)
|
||||||
|
* @param {React.ReactNode} props.footer - Custom footer content
|
||||||
|
* @param {Object} props.headerStyle - Additional styles for the header
|
||||||
|
* @param {Object} props.contentStyle - Additional styles for the content
|
||||||
|
* @param {Object} props.footerStyle - Additional styles for the footer
|
||||||
|
* @param {Object} props.breakpoints - Responsive breakpoints (e.g. {'960px': '75vw'})
|
||||||
|
* @param {boolean} props.modal - Whether the modal requires a click on the mask to hide
|
||||||
|
* @param {boolean} props.draggable - Whether the modal is draggable
|
||||||
|
* @param {boolean} props.resizable - Whether the modal is resizable
|
||||||
|
* @param {boolean} props.maximizable - Whether the modal can be maximized
|
||||||
|
* @param {boolean} props.dismissableMask - Whether clicking outside closes the modal
|
||||||
|
* @param {boolean} props.showCloseButton - Whether to show the default close button in the footer
|
||||||
|
*/
|
||||||
|
const Modal = ({
|
||||||
|
header,
|
||||||
|
visible,
|
||||||
|
onHide,
|
||||||
|
children,
|
||||||
|
className = '',
|
||||||
|
style = {},
|
||||||
|
width = 'fit',
|
||||||
|
footer,
|
||||||
|
headerStyle = {},
|
||||||
|
contentStyle = {},
|
||||||
|
footerStyle = {},
|
||||||
|
breakpoints,
|
||||||
|
modal,
|
||||||
|
draggable,
|
||||||
|
resizable,
|
||||||
|
maximizable,
|
||||||
|
dismissableMask,
|
||||||
|
showCloseButton = false,
|
||||||
|
...otherProps
|
||||||
|
}) => {
|
||||||
|
// Base dark styling
|
||||||
|
const baseStyle = { backgroundColor: '#1f2937' };
|
||||||
|
const baseHeaderStyle = { backgroundColor: '#1f2937', color: 'white' };
|
||||||
|
const baseContentStyle = { backgroundColor: '#1f2937' };
|
||||||
|
const baseFooterStyle = { backgroundColor: '#1f2937', borderTop: '1px solid #374151' };
|
||||||
|
|
||||||
|
// Determine width class
|
||||||
|
let widthClass = '';
|
||||||
|
if (width === 'fit') {
|
||||||
|
widthClass = 'w-fit';
|
||||||
|
} else if (width === 'full') {
|
||||||
|
widthClass = 'w-full';
|
||||||
|
} else {
|
||||||
|
// Custom width will be handled via style
|
||||||
|
style.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create footer with close button if requested
|
||||||
|
const footerContent = showCloseButton ? (
|
||||||
|
<div className="flex justify-end w-full">
|
||||||
|
<Button
|
||||||
|
label="Close"
|
||||||
|
icon="pi pi-times"
|
||||||
|
onClick={onHide}
|
||||||
|
className="p-button-text text-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : footer;
|
||||||
|
|
||||||
|
// Apply tailwind CSS to modify dialog elements
|
||||||
|
const dialogClassNames = `
|
||||||
|
.p-dialog-footer {
|
||||||
|
background-color: #1f2937 !important;
|
||||||
|
border-top: 1px solid #374151 !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<style jsx global>{dialogClassNames}</style>
|
||||||
|
<Dialog
|
||||||
|
header={header}
|
||||||
|
visible={visible}
|
||||||
|
onHide={onHide}
|
||||||
|
className={`p-fluid pb-0 ${widthClass} ${className}`}
|
||||||
|
style={{ ...baseStyle, ...style }}
|
||||||
|
headerStyle={{ ...baseHeaderStyle, ...headerStyle }}
|
||||||
|
contentStyle={{ ...baseContentStyle, ...contentStyle }}
|
||||||
|
footerStyle={{ ...baseFooterStyle, ...footerStyle }}
|
||||||
|
footer={footerContent}
|
||||||
|
breakpoints={breakpoints}
|
||||||
|
modal={modal}
|
||||||
|
draggable={draggable}
|
||||||
|
resizable={resizable}
|
||||||
|
maximizable={maximizable}
|
||||||
|
dismissableMask={dismissableMask}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
Loading…
x
Reference in New Issue
Block a user