= ({
13 | isActive,
14 | onChange,
15 | mode,
16 | }) => {
17 | if (mode === 'blacklist') {
18 | return null;
19 | }
20 |
21 | return (
22 |
23 | onChange(checked)}
28 | />
29 |
30 | );
31 | };
32 |
33 | export default MediaToggle;
34 |
--------------------------------------------------------------------------------
/src/components/relay-settings/sections/MediaSection/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/sections/MediaSection/index.ts
2 |
3 | import MediaSection from './MediaSection';
4 | export { MediaSection };
--------------------------------------------------------------------------------
/src/components/relay-settings/sections/ModerationSection/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/sections/ModerationSection/index.ts
2 |
3 | export * from './ModerationSection';
4 | export { default } from './ModerationSection';
5 |
--------------------------------------------------------------------------------
/src/components/relay-settings/sections/NetworkSection/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/sections/NetworkSection/index.ts
2 |
3 | import NetworkSection from './NetworkSection';
4 | export { NetworkSection };
5 |
--------------------------------------------------------------------------------
/src/components/relay-settings/sections/SubscriptionSection/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/sections/SubscriptionSection/index.ts
2 |
3 | import SubscriptionSection from './SubscriptionSection';
4 | export { SubscriptionSection };
--------------------------------------------------------------------------------
/src/components/relay-settings/shared/CollapsibleSection/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/shared/CollapsibleSection/index.ts
2 |
3 | export { default as CollapsibleSection } from './CollapsibleSection';
4 | export type { CollapsibleSectionProps } from './CollapsibleSection';
--------------------------------------------------------------------------------
/src/components/relay-settings/shared/SectionCard/index.ts:
--------------------------------------------------------------------------------
1 | // src/components/relay-settings/shared/SectionCard/index.ts
2 |
3 | export { default as SectionCard } from './SectionCard';
4 | export type { SectionCardProps } from './SectionCard';
5 | export * from './SectionCard.styles';
--------------------------------------------------------------------------------
/src/components/report/ReportNotifications/index.ts:
--------------------------------------------------------------------------------
1 | import { ReportNotifications } from './ReportNotifications';
2 |
3 | export default ReportNotifications;
4 |
--------------------------------------------------------------------------------
/src/components/router/Logout.tsx:
--------------------------------------------------------------------------------
1 | // Logout.tsx
2 | import React, { useEffect } from 'react';
3 | import { useAppDispatch } from '@app/hooks/reduxHooks';
4 | import { Navigate } from 'react-router-dom';
5 | import { doLogout } from '@app/store/slices/authSlice';
6 |
7 | const Logout: React.FC = () => {
8 | const dispatch = useAppDispatch();
9 |
10 | useEffect(() => {
11 | const logoutAndReload = async () => {
12 | await dispatch(doLogout());
13 | window.location.reload(); // Reload the page to clear any persisted state
14 | };
15 |
16 | logoutAndReload();
17 | }, [dispatch]);
18 |
19 | return ;
20 | };
21 |
22 | export default Logout;
23 |
--------------------------------------------------------------------------------
/src/config/config.ts:
--------------------------------------------------------------------------------
1 | // config.ts
2 | const config = {
3 | baseURL: process.env.REACT_APP_DEMO_MODE === 'true'
4 | ? 'http://localhost:10002'
5 | : process.env.NODE_ENV === 'production'
6 | ? window.location.origin || 'http://localhost:9002'
7 | : process.env.REACT_APP_BASE_URL || 'http://localhost:9002',
8 | isDemoMode: process.env.REACT_APP_DEMO_MODE === 'true',
9 | walletBaseURL: process.env.REACT_APP_WALLET_BASE_URL?.trim() || 'http://localhost:9003',
10 |
11 | // Notification settings
12 | notifications: {
13 | // 5 minutes in milliseconds
14 | pollingInterval: 5 * 60 * 1000,
15 | // Decrease polling frequency when tab is not focused
16 | backgroundPollingInterval: 15 * 60 * 1000,
17 | },
18 | };
19 |
20 | export default config;
21 |
--------------------------------------------------------------------------------
/src/constants/categoriesList.ts:
--------------------------------------------------------------------------------
1 | export type CategoryType = 'apps' | 'forms' | 'charts' | 'auth' | 'data tables' | 'maps';
2 |
3 | interface Category {
4 | name: CategoryType;
5 | title: string;
6 | }
7 |
8 | export const categoriesList: Category[] = [
9 | {
10 | name: 'apps',
11 | title: 'common.apps',
12 | },
13 | {
14 | name: 'auth',
15 | title: 'common.auth',
16 | },
17 | {
18 | name: 'forms',
19 | title: 'common.forms',
20 | },
21 | {
22 | name: 'data tables',
23 | title: 'common.dataTables',
24 | },
25 | {
26 | name: 'charts',
27 | title: 'common.charts',
28 | },
29 | {
30 | name: 'maps',
31 | title: 'common.maps',
32 | },
33 | ];
34 |
--------------------------------------------------------------------------------
/src/constants/config/activityStatuses.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DollarOutlined, PlusOutlined, ReadOutlined } from '@ant-design/icons';
3 | import { ActivityStatusType } from '@app/interfaces/interfaces';
4 |
5 | interface ActivityStatusItem {
6 | name: ActivityStatusType;
7 | title: string;
8 | color: 'success' | 'warning' | 'secondary';
9 | icon: React.ReactNode;
10 | }
11 |
12 | export const activityStatuses: ActivityStatusItem[] = [
13 | {
14 | name: 'sold',
15 | title: 'nft.status.sold',
16 | color: 'success',
17 | icon: ,
18 | },
19 | {
20 | name: 'added',
21 | title: 'nft.status.added',
22 | color: 'warning',
23 | icon: ,
24 | },
25 | {
26 | name: 'booked',
27 | title: 'nft.status.booked',
28 | color: 'secondary',
29 | icon: ,
30 | },
31 | ];
32 |
--------------------------------------------------------------------------------
/src/constants/config/currencies.ts:
--------------------------------------------------------------------------------
1 | import { CurrencyTypeEnum } from '@app/interfaces/interfaces';
2 |
3 | export const currencies = {
4 | [CurrencyTypeEnum.USD]: {
5 | text: 'USD',
6 | icon: '$',
7 | },
8 | [CurrencyTypeEnum.BTC]: {
9 | text: 'BTC',
10 | icon: '₿',
11 | },
12 | [CurrencyTypeEnum.ETH]: {
13 | text: 'ETH',
14 | icon: 'Ξ',
15 | },
16 | [CurrencyTypeEnum.SATS]: {
17 | text: 'SATS',
18 | icon: 'SAT ',
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/src/constants/defaultPaddings.ts:
--------------------------------------------------------------------------------
1 | interface DefaultPadding {
2 | mobile: [number, number];
3 | tablet: [number, number];
4 | desktop: [number, number];
5 | }
6 |
7 | export const defaultPaddings: DefaultPadding = {
8 | mobile: [30, 16],
9 | tablet: [40, 30],
10 | desktop: [50, 60],
11 | };
12 |
--------------------------------------------------------------------------------
/src/constants/enums/priorities.ts:
--------------------------------------------------------------------------------
1 | export enum Priority {
2 | INFO,
3 | LOW,
4 | MEDIUM,
5 | HIGH,
6 | }
7 |
--------------------------------------------------------------------------------
/src/constants/healthChartData.ts:
--------------------------------------------------------------------------------
1 | export interface HealthFactor {
2 | value: number;
3 | name: string;
4 | description: string;
5 | }
6 |
7 | export const healthChartData: HealthFactor[] = [
8 | {
9 | value: 50,
10 | name: 'medical-dashboard.health.lifestyle.title',
11 | description: 'medical-dashboard.health.lifestyle.description',
12 | },
13 | {
14 | value: 20,
15 | name: 'medical-dashboard.health.ecology.title',
16 | description: 'medical-dashboard.health.ecology.description',
17 | },
18 | {
19 | value: 20,
20 | name: 'medical-dashboard.health.genetics.title',
21 | description: 'medical-dashboard.health.genetics.description',
22 | },
23 | {
24 | value: 10,
25 | name: 'medical-dashboard.health.medicine.title',
26 | description: 'medical-dashboard.health.medicine.description',
27 | },
28 | ];
29 |
--------------------------------------------------------------------------------
/src/constants/languages.ts:
--------------------------------------------------------------------------------
1 | import { LanguageType } from '@app/interfaces/interfaces';
2 |
3 | interface Language {
4 | id: number;
5 | name: LanguageType;
6 | title: string;
7 | countryCode: string;
8 | }
9 |
10 | export const languages: Language[] = [
11 | {
12 | id: 1,
13 | name: 'en',
14 | title: 'English',
15 | countryCode: 'gb',
16 | },
17 | {
18 | id: 2,
19 | name: 'de',
20 | title: 'German',
21 | countryCode: 'de',
22 | },
23 | ];
24 |
--------------------------------------------------------------------------------
/src/constants/maxNews.ts:
--------------------------------------------------------------------------------
1 | export const MAX_NEWS = 6;
2 |
--------------------------------------------------------------------------------
/src/constants/modalSizes.ts:
--------------------------------------------------------------------------------
1 | interface ModalSizes {
2 | small: string;
3 | medium: string;
4 | large: string;
5 | }
6 |
7 | export const modalSizes: ModalSizes = {
8 | small: '400px',
9 | medium: '600px',
10 | large: '800px',
11 | };
12 |
--------------------------------------------------------------------------------
/src/constants/newsTags.ts:
--------------------------------------------------------------------------------
1 | // TODO add i18n
2 |
3 | interface Tag {
4 | id: string;
5 | title: string;
6 | bgColor: 'error' | 'warning' | 'success';
7 | }
8 |
9 | interface NewsTags {
10 | [key: string]: Tag;
11 | }
12 |
13 | export const newsTags: NewsTags = {
14 | arts: {
15 | id: 'Arts',
16 | title: 'arts',
17 | bgColor: 'error',
18 | },
19 | music: {
20 | id: 'music',
21 | title: 'music',
22 | bgColor: 'warning',
23 | },
24 | health: {
25 | id: 'health',
26 | title: 'health',
27 | bgColor: 'success',
28 | },
29 | covid: {
30 | id: 'covid',
31 | title: 'COVID',
32 | bgColor: 'error',
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/src/constants/notificationsSeverities.ts:
--------------------------------------------------------------------------------
1 | import { NotificationType } from '@app/components/common/BaseNotification/BaseNotification';
2 |
3 | interface NotificationSeverity {
4 | id: number;
5 | name: NotificationType;
6 | }
7 |
8 | export const notificationsSeverities: NotificationSeverity[] = [
9 | {
10 | id: 0,
11 | name: 'info',
12 | },
13 | {
14 | id: 1,
15 | name: 'success',
16 | },
17 | {
18 | id: 2,
19 | name: 'warning',
20 | },
21 | {
22 | id: 3,
23 | name: 'error',
24 | },
25 | {
26 | id: 4,
27 | name: 'mention',
28 | },
29 | {
30 | id: 5,
31 | name: 'moderation',
32 | },
33 | ];
34 |
--------------------------------------------------------------------------------
/src/constants/patientResultStatus.ts:
--------------------------------------------------------------------------------
1 | interface ResultStatus {
2 | id: number;
3 | name: string;
4 | desc: string;
5 | }
6 |
7 | export const patientResultStatus: ResultStatus[] = [
8 | {
9 | id: 1,
10 | name: 'medical-dashboard.patientResults.patientAdmission.title',
11 | desc: 'medical-dashboard.patientResults.patientAdmission.description',
12 | },
13 | {
14 | id: 2,
15 | name: 'medical-dashboard.patientResults.treatmentStarts.title',
16 | desc: 'medical-dashboard.patientResults.treatmentStarts.description',
17 | },
18 | {
19 | id: 3,
20 | name: 'medical-dashboard.patientResults.patientDischarge.title',
21 | desc: 'medical-dashboard.patientResults.patientDischarge.description',
22 | },
23 | ];
24 |
--------------------------------------------------------------------------------
/src/constants/patientResultsData.tsx:
--------------------------------------------------------------------------------
1 | interface Result {
2 | id: number;
3 | status: number;
4 | date: number;
5 | isActive: boolean;
6 | }
7 |
8 | export const patientResultsData: Array = [
9 | {
10 | id: 1,
11 | status: 1,
12 | date: Date.now(),
13 | isActive: true,
14 | },
15 | {
16 | id: 2,
17 | status: 2,
18 | date: Date.now(),
19 | isActive: false,
20 | },
21 | {
22 | id: 3,
23 | status: 3,
24 | date: Date.now() + 5 * 24 * 3600 * 1000,
25 | isActive: false,
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/constants/patterns.ts:
--------------------------------------------------------------------------------
1 | export const passwordPattern = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/);
2 |
3 | export const websitePattern = /[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)?/gi;
4 |
--------------------------------------------------------------------------------
/src/constants/paymentStatuses.ts:
--------------------------------------------------------------------------------
1 | import { Priority } from './enums/priorities';
2 |
3 | export interface PaymentStatus {
4 | id: number;
5 | name: string;
6 | priority: Priority;
7 | }
8 |
9 | export const paymentStatuses: PaymentStatus[] = [
10 | {
11 | id: 1,
12 | name: 'profile.nav.payments.status.paid',
13 | priority: Priority.LOW,
14 | },
15 | {
16 | id: 2,
17 | name: 'profile.nav.payments.status.scheduled',
18 | priority: Priority.INFO,
19 | },
20 | {
21 | id: 3,
22 | name: 'profile.nav.payments.status.pending',
23 | priority: Priority.MEDIUM,
24 | },
25 | {
26 | id: 4,
27 | name: 'profile.nav.payments.status.failed',
28 | priority: Priority.HIGH,
29 | },
30 | ];
31 |
--------------------------------------------------------------------------------
/src/constants/polyclinicsData.ts:
--------------------------------------------------------------------------------
1 | interface Polyclinic {
2 | id: number;
3 | name: string;
4 | gps: {
5 | latitude: number;
6 | longitude: number;
7 | };
8 | }
9 |
10 | export const polyclinicData: Polyclinic[] = [
11 | {
12 | id: 1,
13 | name: '42',
14 | gps: {
15 | latitude: 42.333804,
16 | longitude: -83.042268,
17 | },
18 | },
19 | {
20 | id: 2,
21 | name: '14',
22 | gps: {
23 | latitude: 42.331916,
24 | longitude: -83.038296,
25 | },
26 | },
27 | {
28 | id: 3,
29 | name: '26',
30 | gps: {
31 | latitude: 42.349918,
32 | longitude: -83.025836,
33 | },
34 | },
35 | ];
36 |
--------------------------------------------------------------------------------
/src/constants/specifities.ts:
--------------------------------------------------------------------------------
1 | interface Specifity {
2 | id: number;
3 | name: string;
4 | }
5 |
6 | export const specifities: Specifity[] = [
7 | {
8 | id: 1,
9 | name: 'surgeon',
10 | },
11 | {
12 | id: 2,
13 | name: 'dermatologist',
14 | },
15 | {
16 | id: 3,
17 | name: 'oncologist',
18 | },
19 | {
20 | id: 4,
21 | name: 'cardiologist',
22 | },
23 | {
24 | id: 5,
25 | name: 'therapist',
26 | },
27 | {
28 | id: 6,
29 | name: 'ophthalmologist',
30 | },
31 | {
32 | id: 7,
33 | name: 'neurologist',
34 | },
35 | ];
36 |
--------------------------------------------------------------------------------
/src/domain/UserModel.ts:
--------------------------------------------------------------------------------
1 | export interface UserModel {
2 | id: number;
3 | firstName: string;
4 | lastName: string;
5 | userName: string;
6 | role: string;
7 | email: string;
8 | imgUrl?: string;
9 | }
10 |
--------------------------------------------------------------------------------
/src/hocs/withLoading.hoc.tsx:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from 'react';
2 | import { Loading } from '@app/components/common/Loading/Loading';
3 |
4 | type WithLoadingProps = T & { children?: React.ReactNode };
5 |
6 | const withLoading = (Component: React.ComponentType) => {
7 | const WithLoadingComponent = (props: WithLoadingProps) => {
8 | console.log(`Rendering withLoading for`, Component.displayName || Component.name || 'UnnamedComponent');
9 | return (
10 | }>
11 |
12 |
13 | );
14 | };
15 |
16 | // Set a display name for easier debugging
17 | WithLoadingComponent.displayName = `WithLoading(${Component.displayName || Component.name || 'UnnamedComponent'})`;
18 |
19 | return WithLoadingComponent;
20 | };
21 |
22 | export { withLoading };
23 |
24 |
--------------------------------------------------------------------------------
/src/hooks/authUtils.ts:
--------------------------------------------------------------------------------
1 | import { useAppDispatch } from '@app/hooks/reduxHooks'; // Make sure your hook path is correct
2 | import { doLogout } from '@app/store/slices/authSlice'; // Adjust the path as necessary
3 | import { message } from 'antd';
4 | import { useCallback } from 'react';
5 |
6 | export const useHandleLogout = () => {
7 | const dispatch = useAppDispatch();
8 |
9 | const handleLogout = useCallback(() => {
10 | dispatch(doLogout())
11 | .unwrap()
12 | .then(() => {
13 | message.info('You have been logged out. Please login again.');
14 | })
15 | .catch((error) => {
16 | console.error('Logout error:', error);
17 | message.error('An error occurred during logout.');
18 | });
19 | }, [dispatch]); // Memoize the function, so it's only recreated if dispatch changes
20 |
21 | return handleLogout;
22 | };
23 |
--------------------------------------------------------------------------------
/src/hooks/reduxHooks.ts:
--------------------------------------------------------------------------------
1 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
2 | import type { RootState, AppDispatch } from '../store/store';
3 |
4 | // Use throughout your app instead of plain `useDispatch` and `useSelector`
5 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
6 | export const useAppDispatch = () => useDispatch();
7 | export const useAppSelector: TypedUseSelectorHook = useSelector;
8 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 |
3 | function useDebounce(value: T, delay: number): T {
4 | const [debouncedValue, setDebouncedValue] = useState(value);
5 |
6 | useEffect(() => {
7 | const timer = setTimeout(() => setDebouncedValue(value), delay);
8 |
9 | return () => {
10 | clearTimeout(timer);
11 | };
12 | }, [value, delay]);
13 |
14 | return debouncedValue;
15 | }
16 |
17 | export default useDebounce;
18 |
--------------------------------------------------------------------------------
/src/hooks/useMounted.ts:
--------------------------------------------------------------------------------
1 | import { MutableRefObject, useEffect, useRef } from 'react';
2 |
3 | interface UseMountedReturnVal {
4 | isMounted: MutableRefObject;
5 | }
6 |
7 | export const useMounted = (): UseMountedReturnVal => {
8 | const isMounted = useRef(false);
9 |
10 | useEffect(() => {
11 | isMounted.current = true;
12 |
13 | return () => {
14 | isMounted.current = false;
15 | };
16 | }, []);
17 |
18 | return { isMounted };
19 | };
20 |
--------------------------------------------------------------------------------
/src/hooks/useOnClickOutside.ts:
--------------------------------------------------------------------------------
1 | import { RefObject, useEffect } from 'react';
2 |
3 | type AnyEvent = MouseEvent | TouchEvent;
4 |
5 | function useOnClickOutside(
6 | ref: RefObject,
7 | handler: (event: AnyEvent) => void,
8 | ): void {
9 | useEffect(() => {
10 | const listener = (event: AnyEvent) => {
11 | const el = ref?.current;
12 |
13 | // Do nothing if clicking ref's element or descendent elements
14 | if (!el || el.contains(event.target as Node)) {
15 | return;
16 | }
17 |
18 | handler(event);
19 | };
20 |
21 | document.addEventListener(`mousedown`, listener);
22 | document.addEventListener(`touchstart`, listener);
23 |
24 | return () => {
25 | document.removeEventListener(`mousedown`, listener);
26 | document.removeEventListener(`touchstart`, listener);
27 | };
28 |
29 | // Reload only if ref or handler changes
30 | }, [ref, handler]);
31 | }
32 |
33 | export { useOnClickOutside };
34 |
--------------------------------------------------------------------------------
/src/hooks/useTrendingCreators.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @deprecated This hook has been renamed to usePaidSubscribers as it retrieves paid subscriber profiles, not trending creators.
3 | * Please use the usePaidSubscribers hook instead.
4 | */
5 |
6 | import usePaidSubscribers, { SubscriberProfile } from './usePaidSubscribers';
7 |
8 | // Re-export the hook with the old name for backward compatibility
9 | export default usePaidSubscribers;
10 |
11 | // Re-export the types
12 | export type { SubscriberProfile as CreatorProfile } from './usePaidSubscribers';
13 |
--------------------------------------------------------------------------------
/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import i18n from 'i18next';
2 | import { initReactI18next } from 'react-i18next';
3 |
4 | import translationEN from './locales/en/translation.json';
5 | import translationDE from './locales/de/translation.json';
6 |
7 | const resources = {
8 | en: {
9 | translation: translationEN,
10 | },
11 | de: {
12 | translation: translationDE,
13 | },
14 | };
15 |
16 | i18n.use(initReactI18next).init({
17 | resources,
18 | lng: 'en',
19 |
20 | interpolation: {
21 | escapeValue: false,
22 | },
23 | });
24 |
25 | export default i18n;
26 |
--------------------------------------------------------------------------------
/src/pages/BlockedPubkeysPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { BlockedPubkeys } from '@app/components/blocked-pubkeys';
5 |
6 | const BlockedPubkeysPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.blockedPubkeys', 'Blocked Pubkeys')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default BlockedPubkeysPage;
18 |
--------------------------------------------------------------------------------
/src/pages/Error404Page.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { Error } from '@app/components/Error/Error';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 | import error404 from '@app/assets/images/error404.svg';
6 |
7 | const Error404Page: React.FC = () => {
8 | const { t } = useTranslation();
9 |
10 | return (
11 | <>
12 | {t('common.clientError')}
13 |
14 | >
15 | );
16 | };
17 |
18 | export default Error404Page;
19 |
--------------------------------------------------------------------------------
/src/pages/ForgotPasswordPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { ForgotPasswordForm } from '@app/components/auth/ForgotPasswordForm/ForgotPasswordForm';
5 |
6 | const ForgotPasswordPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.forgotPass')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default ForgotPasswordPage;
18 |
--------------------------------------------------------------------------------
/src/pages/LockPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { LockForm } from '@app/components/auth/LockForm/LockForm';
5 |
6 | const LockPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.lock')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default LockPage;
18 |
--------------------------------------------------------------------------------
/src/pages/LoginPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { LoginForm } from '@app/components/auth/LoginForm/LoginForm';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const LoginPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.login')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default LoginPage;
18 |
--------------------------------------------------------------------------------
/src/pages/MediaPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import MediaLayout from '@app/components/media/MediaLayout';
3 | const MediaPage: React.FC = () => {
4 | return (
5 | <>
6 |
7 | >
8 | );
9 | };
10 |
11 | export default MediaPage;
--------------------------------------------------------------------------------
/src/pages/NewPasswordPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NewPasswordForm } from '@app/components/auth/NewPasswordForm/NewPasswordForm';
3 | import { useTranslation } from 'react-i18next';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const NewPasswordPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.newPassword')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default NewPasswordPage;
18 |
--------------------------------------------------------------------------------
/src/pages/NewsFeedPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { NewsFeed } from '@app/components/apps/newsFeed/NewsFeed';
5 |
6 | const NewsFeedPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.feed')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default NewsFeedPage;
18 |
--------------------------------------------------------------------------------
/src/pages/NotificationsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Notifications } from '@app/components/profile/profileCard/profileFormNav/nav/notifications/Notifications/Notifications';
3 | import { useTranslation } from 'react-i18next';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const NotificationsPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('profile.nav.notifications.title')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default NotificationsPage;
18 |
--------------------------------------------------------------------------------
/src/pages/PaymentNotificationsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { PaymentNotifications } from '@app/components/payment/PaymentNotifications';
3 |
4 | const PaymentNotificationsPage: React.FC = () => {
5 | return (
6 |
7 | );
8 | };
9 |
10 | export default PaymentNotificationsPage;
11 |
--------------------------------------------------------------------------------
/src/pages/PaymentsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { Payments } from '@app/components/profile/profileCard/profileFormNav/nav/payments/Payments';
5 |
6 | const PaymentsPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('profile.nav.payments.title')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default PaymentsPage;
18 |
--------------------------------------------------------------------------------
/src/pages/PersonalInfoPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PersonalInfo } from '@app/components/profile/profileCard/profileFormNav/nav/PersonalInfo/PersonalInfo';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const PersonalInfoPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('profile.nav.personalInfo.title')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default PersonalInfoPage;
18 |
--------------------------------------------------------------------------------
/src/pages/ReportNotificationsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
3 | import ReportNotifications from '@app/components/report/ReportNotifications';
4 | import { useTranslation } from 'react-i18next';
5 |
6 | const ReportNotificationsPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('report.notifications.pageTitle', 'Content Reports')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default ReportNotificationsPage;
18 |
--------------------------------------------------------------------------------
/src/pages/SecurityCodePage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SecurityCodeForm } from '@app/components/auth/SecurityCodeForm/SecurityCodeForm';
3 | import { useTranslation } from 'react-i18next';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const SecurityCodePage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.securityCode')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default SecurityCodePage;
18 |
--------------------------------------------------------------------------------
/src/pages/SecuritySettingsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { SecuritySettings } from '@app/components/profile/profileCard/profileFormNav/nav/SecuritySettings/SecuritySettings';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 |
6 | const SecuritySettingsPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('profile.nav.securitySettings.title')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default SecuritySettingsPage;
18 |
--------------------------------------------------------------------------------
/src/pages/ServerErrorPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { Error } from '@app/components/Error/Error';
4 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
5 | import serverError from '@app/assets/images/server-error.svg';
6 |
7 | const ServerErrorPage: React.FC = () => {
8 | const { t } = useTranslation();
9 |
10 | return (
11 | <>
12 | {t('common.serverError')}
13 |
14 | >
15 | );
16 | };
17 |
18 | export default ServerErrorPage;
19 |
--------------------------------------------------------------------------------
/src/pages/SignUpPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PageTitle } from '@app/components/common/PageTitle/PageTitle';
4 | import { SignUpForm } from '@app/components/auth/SignUpForm/SignUpForm';
5 |
6 | const SignUpPage: React.FC = () => {
7 | const { t } = useTranslation();
8 |
9 | return (
10 | <>
11 | {t('common.signUp')}
12 |
13 | >
14 | );
15 | };
16 |
17 | export default SignUpPage;
18 |
--------------------------------------------------------------------------------
/src/pages/maps/maps.styles.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { BaseCard } from '@app/components/common/BaseCard/BaseCard';
3 |
4 | export const MapsCard = styled(BaseCard)`
5 | height: 70vh;
6 | overflow-y: auto;
7 |
8 | .leaflet-container {
9 | z-index: 0;
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
4 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
5 | if (onPerfEntry) {
6 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
7 | getCLS(onPerfEntry);
8 | getFID(onPerfEntry);
9 | getFCP(onPerfEntry);
10 | getLCP(onPerfEntry);
11 | getTTFB(onPerfEntry);
12 | });
13 | }
14 | };
15 |
16 | export default reportWebVitals;
17 |
--------------------------------------------------------------------------------
/src/services/authService.ts:
--------------------------------------------------------------------------------
1 | // src/services/authService.ts
2 | import axios from 'axios';
3 | import config from '@app/config/config';
4 |
5 | export const isUserExist = async (): Promise => {
6 | try {
7 | const response = await axios.get(`${config.baseURL}/user-exist`);
8 | return response.data.exists;
9 | } catch (error) {
10 | console.error('Error checking user existence', error);
11 | return false;
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/store/middlewares/errorLogging.middleware.ts:
--------------------------------------------------------------------------------
1 | import { isRejectedWithValue, Middleware } from '@reduxjs/toolkit';
2 | import { notificationController } from '@app/controllers/notificationController';
3 |
4 | /**
5 | * Log a warning and show a toast!
6 | */
7 | export const errorLoggingMiddleware: Middleware = () => (next) => (action) => {
8 | if (isRejectedWithValue(action)) {
9 | notificationController.error({ message: action.payload });
10 | }
11 |
12 | return next(action);
13 | };
14 |
--------------------------------------------------------------------------------
/src/store/slices/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from '@reduxjs/toolkit';
2 | import userReducer from '@app/store/slices/userSlice';
3 | import authReducer from '@app/store/slices/authSlice';
4 | import nightModeReducer from '@app/store/slices/nightModeSlice';
5 | import themeReducer from '@app/store/slices/themeSlice';
6 | import pwaReducer from '@app/store/slices/pwaSlice';
7 | import serverModeReducer from '@app/store/slices/modeSlice';
8 |
9 | // Combine all slice reducers into a single root reducer
10 | const rootReducer = combineReducers({
11 | user: userReducer,
12 | auth: authReducer,
13 | nightMode: nightModeReducer,
14 | theme: themeReducer,
15 | pwa: pwaReducer,
16 | mode: serverModeReducer, // Make sure this name matches what you use in your selectors
17 | });
18 |
19 | export default rootReducer;
20 |
--------------------------------------------------------------------------------
/src/store/slices/userSlice.ts:
--------------------------------------------------------------------------------
1 | import { createAction, createSlice, PrepareAction } from '@reduxjs/toolkit';
2 | import { UserModel } from '@app/domain/UserModel';
3 | import { persistUser, readUser } from '@app/services/localStorage.service';
4 |
5 | export interface UserState {
6 | user: UserModel | null;
7 | }
8 |
9 | const initialState: UserState = {
10 | user: readUser(),
11 | };
12 |
13 | export const setUser = createAction>('user/setUser', (newUser) => {
14 | persistUser(newUser);
15 |
16 | return {
17 | payload: newUser,
18 | };
19 | });
20 |
21 | export const userSlice = createSlice({
22 | name: 'user',
23 | initialState,
24 | reducers: {},
25 | extraReducers: (builder) => {
26 | builder.addCase(setUser, (state, action) => {
27 | state.user = action.payload;
28 | });
29 | },
30 | });
31 |
32 | export default userSlice.reducer;
33 |
--------------------------------------------------------------------------------
/src/styles/resetCss.ts:
--------------------------------------------------------------------------------
1 | import { css } from 'styled-components';
2 |
3 | export const resetCss = css`
4 | * {
5 | box-sizing: border-box;
6 | margin: 0;
7 | padding: 0;
8 | }
9 |
10 | ::-webkit-scrollbar {
11 | width: 1rem;
12 | }
13 | ::-webkit-scrollbar-track {
14 | background-color: transparent;
15 | }
16 | ::-webkit-scrollbar-thumb {
17 | background-color: var(--scroll-color);
18 | border-radius: 1.25rem;
19 | border: 0.375rem solid transparent;
20 | background-clip: content-box;
21 | }
22 |
23 | body {
24 | font-weight: 500;
25 | }
26 |
27 | img {
28 | display: block;
29 | }
30 | `;
31 |
--------------------------------------------------------------------------------
/src/styles/themes/main.less:
--------------------------------------------------------------------------------
1 | // default antd styles
2 | // @import 'node_modules/antd/lib/style/themes/default.less';
3 | @import 'node_modules/antd/dist/antd.variable.less';
4 |
5 | // common variables
6 | @import '../_override_variables.less';
7 |
8 |
--------------------------------------------------------------------------------
/src/types/generalTypes.ts:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | export type WithChildrenProps = T extends undefined
4 | ? {
5 | children?: ReactNode;
6 | }
7 | : T & {
8 | children?: ReactNode;
9 | };
10 |
--------------------------------------------------------------------------------
/src/types/modeTypes.ts:
--------------------------------------------------------------------------------
1 | // Define the state and action types for mode settings
2 | export interface ModeState {
3 | relayMode: 'blacklist' | 'whitelist';
4 | kinds: number[];
5 | mediaTypes: string[];
6 | }
7 |
8 | export interface ModeAction {
9 | type: string;
10 | payload: any;
11 | }
12 |
--------------------------------------------------------------------------------
/src/types/nostr.ts:
--------------------------------------------------------------------------------
1 | // src/types/nostr.ts
2 | export interface NostrProvider {
3 | getPublicKey: () => Promise;
4 | signEvent: (event: any) => Promise;
5 | getRelays: () => Promise>;
6 | nip04?: {
7 | encrypt?: (pubkey: string, content: string) => Promise;
8 | decrypt?: (pubkey: string, content: string) => Promise;
9 | };
10 | nip44?: {
11 | encrypt?: (pubkey: string, content: string) => Promise;
12 | decrypt?: (pubkey: string, content: string) => Promise;
13 | };
14 | }
15 |
16 | declare global {
17 | interface Window {
18 | nostr?: NostrProvider;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/utils/balanceFormatter.ts:
--------------------------------------------------------------------------------
1 | export const formatBalance = (balance: number): string => {
2 | if (balance >= 1e6) {
3 | return `${(balance / 1e6).toFixed(1)}M Sats`;
4 | } else if (balance >= 1e3) {
5 | return `${(balance / 1e3).toFixed(1)}K Sats`;
6 | } else {
7 | return `${balance.toFixed(2)} Sats`;
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/src/utils/dateFormatter.ts:
--------------------------------------------------------------------------------
1 | // utils/dateFormatter.ts
2 | import { format } from 'date-fns';
3 |
4 | export const formatDate = (timestamp: number): string => {
5 | return format(new Date(timestamp), 'MM/dd/yyyy HH:mm');
6 | };
7 |
--------------------------------------------------------------------------------
/start-app.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set OpenSSL configuration for Node.js >= 17
4 | export NODE_OPTIONS="--openssl-legacy-provider"
5 |
6 | # Start the app
7 | yarn start
8 |
--------------------------------------------------------------------------------
/start.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | REM This script sets the necessary environment variable and starts the React app
3 |
4 | echo Setting OpenSSL legacy provider and increasing memory allocation...
5 | set "NODE_OPTIONS=--openssl-legacy-provider --max-old-space-size=4096"
6 |
7 | REM Run lessc directly using local node_modules
8 | call node_modules\.bin\lessc --js --clean-css="--s1 --advanced" src/styles/themes/main.less public/themes/main.css
9 | if errorlevel 1 goto error
10 |
11 | echo Theme built successfully, starting the app...
12 | call yarn run craco start
13 | if errorlevel 1 goto error
14 | goto end
15 |
16 | :error
17 | echo Failed with error #%errorlevel%.
18 | exit /b %errorlevel%
19 |
20 | :end
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.paths.json",
3 | "compilerOptions": {
4 | "baseUrl": "./src/",
5 | "target": "es5",
6 | "lib": [
7 | "dom",
8 | "dom.iterable",
9 | "esnext"
10 | ],
11 | "allowJs": true,
12 | "skipLibCheck": true,
13 | "esModuleInterop": true,
14 | "allowSyntheticDefaultImports": true,
15 | "strict": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "noFallthroughCasesInSwitch": true,
18 | "module": "esnext",
19 | "moduleResolution": "node",
20 | "resolveJsonModule": true,
21 | "isolatedModules": true,
22 | "noEmit": true,
23 | "jsx": "react-jsx"
24 | },
25 | "include": [
26 | "src"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/tsconfig.paths.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@app/*" : ["./*"]
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------