Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { AlertTriangle, Loader } from 'lucide-react';
import { AlertTriangle } from 'lucide-react';
import { AnimatePresence, motion } from 'motion/react';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { Button } from '@components/button';
import { NavigationBlockerDialog } from '@components/NavigationBlockerDialog';
import { ProcessingSpinner } from '@components/ProcessingSpinner';
import {
ResponsiveDialog,
ResponsiveDialogContent,
Expand Down Expand Up @@ -131,7 +132,7 @@ export function MutationDialog({
<ResponsiveDialogTitle className="sr-only">
{processingMessage}
</ResponsiveDialogTitle>
<AnimatedSpinner />
<ProcessingSpinner />
<FadeInText delay={0.2}>{processingMessage}</FadeInText>
</PhaseContainer>
)}
Expand Down Expand Up @@ -232,19 +233,6 @@ function PhaseContainer({
);
}

function AnimatedSpinner() {
return (
<motion.div
className="flex size-16 items-center justify-center rounded-full bg-primary/10"
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: 'spring', stiffness: 200, damping: 15 }}
>
<Loader className="size-8 animate-spin text-primary" />
</motion.div>
);
}

function AnimatedSuccessIcon() {
return (
<motion.div
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { motion } from 'motion/react';

import { Spinner } from '@components/Spinner';

/**
* The spinner shown while a mutation runs.
*
* Every processing screen uses this one, so a transfer, a stake, and a vote all
* look the same while they wait.
*/
export const ProcessingSpinner = () => (
<motion.div
className="flex size-16 items-center justify-center rounded-full bg-primary/10"
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: 'spring', stiffness: 200, damping: 15 }}
>
<Spinner className="size-8 text-primary" />
Comment thread
yhabib marked this conversation as resolved.
</motion.div>
);
12 changes: 4 additions & 8 deletions src/governance-app-frontend/src/common/components/Sonner.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import {
CircleCheckBig,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from 'lucide-react';
import { CircleCheckBig, InfoIcon, OctagonXIcon, TriangleAlertIcon } from 'lucide-react';
import { Toaster, type ToasterProps } from 'sonner';

import { Spinner } from '@components/Spinner';
import { useTheme } from '@hooks/useTheme';

const Sonner = ({ ...props }: ToasterProps) => {
Expand All @@ -27,7 +22,8 @@ const Sonner = ({ ...props }: ToasterProps) => {
info: <InfoIcon className="size-4" />,
warning: <TriangleAlertIcon className="size-4 text-amber-700 dark:text-amber-400" />,
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
// The toast is already a live region, so the spinner adds no second status.
loading: <Spinner aria-hidden />,
}}
style={
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { nonNullish } from '@dfinity/utils';
import { AlertTriangle, CheckCircle2, Loader } from 'lucide-react';
import { AlertTriangle, CheckCircle2 } from 'lucide-react';
import { AnimatePresence, motion } from 'motion/react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

import { Button } from '@components/button';
import { NavigationBlockerDialog } from '@components/NavigationBlockerDialog';
import { Spinner } from '@components/Spinner';
import { WELCOME_MODAL_STORAGE_KEY } from '@constants/extra';
import { useAdvancedFeatures } from '@hooks/useAdvancedFeatures';
import { useDetectAdvancedFeatures } from '@hooks/useDetectAdvancedFeatures';
Expand Down Expand Up @@ -138,7 +139,8 @@ function DetectingFeatures() {
rotate: { duration: 2, repeat: Infinity, ease: 'linear', delay: 0.4 },
}}
>
<Loader className="size-4 text-primary/50" />
{/* The parent turns the icon, and the text beside it names the wait. */}
<Spinner aria-hidden className="animate-none text-primary/50" />
</motion.div>
</div>
<motion.span
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ProposalInfo, Vote } from '@icp-sdk/canisters/nns';
import { useInternetIdentity } from 'ic-use-internet-identity';
import { CheckCircle, Loader2, ThumbsDown, ThumbsUp, TriangleAlert } from 'lucide-react';
import { CheckCircle, ThumbsDown, ThumbsUp, TriangleAlert } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';

import { Button } from '@components/button';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@components/Card';
import { Spinner } from '@components/Spinner';
import { E8S } from '@constants/extra';
import { formatNumber, formatPercentage } from '@utils/numbers';
import { cn } from '@utils/shadcn';
Expand Down Expand Up @@ -178,7 +179,7 @@ export const ProposalDetailsVoting: React.FC<Props> = ({ proposal }) => {
variant="outline"
>
{isVoting && votingFor === Vote.Yes ? (
<Loader2 className="mr-2 size-4 animate-spin" />
<Spinner className="mr-2" />
) : (
<ThumbsUp className="mr-2 size-4" />
)}
Expand All @@ -197,7 +198,7 @@ export const ProposalDetailsVoting: React.FC<Props> = ({ proposal }) => {
variant="outline"
>
{isVoting && votingFor === Vote.No ? (
<Loader2 className="mr-2 size-4 animate-spin" />
<Spinner className="mr-2" />
) : (
<ThumbsDown className="mr-2 size-4" />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { secondsToDuration } from '@dfinity/utils';
import {
CheckCircle,
Clock,
Loader2,
MessageSquareOff,
ShieldBan,
Tag,
Expand All @@ -18,6 +17,7 @@ import { Badge } from '@components/badge';
import { Button } from '@components/button';
import { Card, CardFooter, CardHeader } from '@components/Card';
import { CertifiedBadge } from '@components/CertifiedBadge';
import { Spinner } from '@components/Spinner';
import { E8S } from '@constants/extra';
import { formatPercentage } from '@utils/numbers';
import { cn } from '@utils/shadcn';
Expand Down Expand Up @@ -210,7 +210,7 @@ export function ProposalListItem({ proposal, certified, isSpam, isNonActionable
variant="outline"
>
{isVoting && votingFor === Vote.Yes ? (
<Loader2 className="mr-2 size-4 animate-spin" />
<Spinner className="mr-2" />
) : (
<ThumbsUp className="mr-2 size-4" />
)}
Expand All @@ -229,7 +229,7 @@ export function ProposalListItem({ proposal, certified, isSpam, isNonActionable
variant="outline"
>
{isVoting && votingFor === Vote.No ? (
<Loader2 className="mr-2 size-4 animate-spin" />
<Spinner className="mr-2" />
) : (
<ThumbsDown className="mr-2 size-4" />
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { NeuronInfo } from '@icp-sdk/canisters/nns';
import { isNullish } from '@dfinity/utils';
import { Link } from '@tanstack/react-router';
import { AlertTriangle, ArrowRight, Clock, Loader2, TrendingDown } from 'lucide-react';
import { AlertTriangle, ArrowRight, Clock, TrendingDown } from 'lucide-react';
import { useTranslation } from 'react-i18next';

import { AnalyticsEvent } from '@features/analytics/events';
import { analytics } from '@features/analytics/service';

import { Alert, AlertDescription, AlertTitle } from '@components/Alert';
import { Button } from '@components/button';
import { Spinner } from '@components/Spinner';
import { useGovernanceEconomics } from '@hooks/governance/useGovernanceEconomics';
import { mapCanisterError } from '@utils/errors';
import {
Expand Down Expand Up @@ -142,7 +143,7 @@ export function FollowingStatusAlert({ neuron, isHotkey }: Props) {
>
{isPending ? (
<>
<Loader2 className="mr-2 size-4 animate-spin" />
<Spinner className="mr-2" />
{t(($) => $.neuron.followingStatus.processing)}
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { NeuronInfo } from '@icp-sdk/canisters/nns';
import { AlertTriangle, Info, Key, Loader2 } from 'lucide-react';
import { AlertTriangle, Info, Key } from 'lucide-react';
import { Trans, useTranslation } from 'react-i18next';

import { Alert, AlertDescription } from '@components/Alert';
import { Button } from '@components/button';
import { Spinner } from '@components/Spinner';
import { mapCanisterError } from '@utils/errors';
import { errorNotification, successNotification } from '@utils/notification';

Expand Down Expand Up @@ -124,7 +125,7 @@ export function NeuronDetailDissolveView({
>
{isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<Spinner className="mr-2" />
{isDissolving
? t(($) => $.neuronDetailModal.dissolve.confirmingStop)
: t(($) => $.neuronDetailModal.dissolve.confirmingStart)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { NeuronInfo } from '@icp-sdk/canisters/nns';
import { AlertTriangle, Key, Loader2 } from 'lucide-react';
import { AlertTriangle, Key } from 'lucide-react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

import { Alert, AlertDescription } from '@components/Alert';
import { Button } from '@components/button';
import { MaxRewardsBadge } from '@components/MaxRewardsBadge';
import { Spinner } from '@components/Spinner';
import { mapCanisterError } from '@utils/errors';
import { getNeuronDissolveDelaySeconds, getNeuronIsMaxDissolveDelay } from '@utils/neuron';
import { errorNotification, successNotification } from '@utils/notification';
Expand Down Expand Up @@ -169,7 +170,7 @@ export function NeuronDetailIncreaseDelayView({
>
{isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<Spinner className="mr-2" />
{t(($) => $.neuronDetailModal.increaseDelay.confirming)}
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NeuronInfo } from '@icp-sdk/canisters/nns';
import { nonNullish } from '@dfinity/utils';
import { AlertTriangle, Info, Loader2 } from 'lucide-react';
import { AlertTriangle, Info } from 'lucide-react';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

Expand All @@ -12,6 +12,7 @@ import { Alert, AlertDescription } from '@components/Alert';
import { AmountInput } from '@components/AmountInput';
import { Button } from '@components/button';
import { Label } from '@components/Label';
import { Spinner } from '@components/Spinner';
import { CANISTER_ID_ICP_LEDGER } from '@constants/canisterIds';
import { E8Sn, ICP_TRANSACTION_FEE } from '@constants/extra';
import { useIcpLedgerAccountBalance } from '@hooks/icpLedger';
Expand Down Expand Up @@ -204,7 +205,7 @@ export function NeuronDetailIncreaseStakeView({ neuron, onSuccess, onProcessingC
>
{isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<Spinner className="mr-2" />
{t(($) => $.neuronDetailModal.increaseStake.confirming)}
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { NeuronInfo } from '@icp-sdk/canisters/nns';
import { Info, Key, Loader2 } from 'lucide-react';
import { Info, Key } from 'lucide-react';
import { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';

import { Alert, AlertDescription } from '@components/Alert';
import { Button } from '@components/button';
import { MaxRewardsBadge } from '@components/MaxRewardsBadge';
import { SegmentedToggle, type SegmentedToggleValue } from '@components/SegmentedToggle';
import { Spinner } from '@components/Spinner';
import { mapCanisterError } from '@utils/errors';
import { getNeuronIsAutoStakingMaturity } from '@utils/neuron';
import { errorNotification, successNotification } from '@utils/notification';
Expand Down Expand Up @@ -127,7 +128,7 @@ export function NeuronDetailMaturityModeView({
>
{isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<Spinner className="mr-2" />
{t(($) => $.neuronDetailModal.maturityMode.confirming)}
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { AlertTriangle, Loader } from 'lucide-react';
import { AlertTriangle } from 'lucide-react';
import { motion } from 'motion/react';
import { useTranslation } from 'react-i18next';

import { AnimatedCheckmark } from '@components/AnimatedCheckmark';
import { Button } from '@components/button';
import { ProcessingSpinner } from '@components/ProcessingSpinner';

import { STAKING_WIZARD_DISSOLVE_DELAY_OPTIONS } from './constants';
import { StakingWizardCreateNeuronStep, StakingWizardFormState } from './types';
Expand Down Expand Up @@ -54,7 +55,7 @@ export function StakingWizardStepConfirmation({
className="flex flex-col items-center gap-6 text-center"
data-testid="staking-wizard-processing"
>
<AnimatedLoader />
<ProcessingSpinner />
<div>
<p className="mb-3 text-lg font-semibold">
{t(($) => $.stakeWizardModal.steps.confirmation.processing.title)}
Expand Down Expand Up @@ -161,19 +162,6 @@ export function StakingWizardStepConfirmation({
);
}

function AnimatedLoader() {
return (
<motion.div
className="flex size-20 items-center justify-center rounded-full bg-green-600/10"
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.3 }}
>
<Loader className="size-10 animate-spin text-green-600" />
</motion.div>
);
}

function AnimatedErrorIcon() {
return (
<motion.div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type NeuronInfo, Topic } from '@icp-sdk/canisters/nns';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AlertTriangle, Loader2, Plus } from 'lucide-react';
import { AlertTriangle, Plus } from 'lucide-react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

Expand All @@ -17,6 +17,7 @@ import {
ResponsiveDialogTitle,
} from '@components/ResponsiveDialog';
import { Skeleton } from '@components/Skeleton';
import { Spinner } from '@components/Spinner';
import { useGovernanceNeurons, useNnsGovernance } from '@hooks/governance';
import { useGovernanceKnownNeurons } from '@hooks/governance/useGovernanceKnownNeurons';
import { errorMessage } from '@utils/error';
Expand Down Expand Up @@ -101,11 +102,7 @@ export function AdvancedFollowingModal({ open, onOpenChange }: Props) {
}}
data-testid="set-followees-btn"
>
{isWaitingForCertifiedData ? (
<Loader2 className="size-4 animate-spin" />
) : (
<Plus className="size-4" />
)}
{isWaitingForCertifiedData ? <Spinner /> : <Plus className="size-4" />}
{isWaitingForCertifiedData
? t(($) => $.voting.manageFollowing.certifying)
: t(($) => $.voting.manageFollowing.setFollowees)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
Circle,
CircleDot,
LinkIcon,
Loader2,
Square,
} from 'lucide-react';
import { useState } from 'react';
Expand All @@ -18,6 +17,7 @@ import { Badge } from '@components/badge';
import { Button } from '@components/button';
import { Card } from '@components/Card';
import { MarkdownRenderer } from '@components/MarkdownRenderer';
import { Spinner } from '@components/Spinner';
import { DASHBOARD_URL } from '@constants/extra';
import { cn } from '@utils/shadcn';
import { safeParseUrl } from '@utils/urls';
Expand Down Expand Up @@ -68,7 +68,7 @@ export const KnownNeuronCard = ({
<div className="flex gap-4">
<div className="flex h-14 shrink-0 items-center pl-5">
{isLoading ? (
<Loader2 className="size-6 animate-spin" />
<Spinner className="size-6" />
) : mode === 'checkbox' ? (
isSelected ? (
<CheckSquare2 className="size-6 text-primary" />
Expand Down
Loading