Skip to content

Commit

Permalink
Feature/loading balls (#387)
Browse files Browse the repository at this point in the history
* feat: create balloon spinner and implement it in scfini scroll

* style: fix main page layout

---------

Co-authored-by: Pjaijai <[email protected]>
  • Loading branch information
Pjaijai and pauljaijai authored Oct 2, 2024
1 parent 092a111 commit 56bbb75
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 8 deletions.
9 changes: 2 additions & 7 deletions client/components/customized-ui/Infinite-scroll/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useI18n } from "@/utils/services/internationalization/client"
import InfiniteScroll from "react-infinite-scroll-component"

import { Badge } from "@/components/ui/badge"
import LoadingBalloonSpinner from "@/components/customized-ui/spinner/ball"

interface IBaseInfiniteScrollProps {
dataLength: number
Expand Down Expand Up @@ -34,13 +35,7 @@ const BaseInfiniteScroll: React.FunctionComponent<IBaseInfiniteScrollProps> = ({
inverse={inverse}
scrollableTarget={scrollableTarget}
loader={
endMessage || (
<div className="mt-4 flex justify-center">
<Badge variant={"outline"} className="flex justify-center">
{t("search.loading")}
</Badge>
</div>
)
endMessage || <LoadingBalloonSpinner isRandom maxRandomBalls={10} />
}
endMessage={
endMessage || (
Expand Down
43 changes: 43 additions & 0 deletions client/components/customized-ui/spinner/ball.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react"
import { render, screen } from "@testing-library/react"

import "@testing-library/jest-dom"
import LoadingBalloonSpinner from "@/components/customized-ui/spinner/ball"

describe("LoadingBalloonSpinner", () => {
it("renders with default props", () => {
render(<LoadingBalloonSpinner />)
const balls = screen.getAllByTestId("spinner-ball")
expect(balls).toHaveLength(5)
expect(balls[0]).toHaveClass("bg-indigo-400")
})

it("renders with custom number of balls", () => {
render(<LoadingBalloonSpinner numberOfBalls={7} />)
const balls = screen.getAllByTestId("spinner-ball")
expect(balls).toHaveLength(7)
})

it("renders with custom color", () => {
render(<LoadingBalloonSpinner color="bg-red-500" />)
const balls = screen.getAllByTestId("spinner-ball")
expect(balls[0]).toHaveClass("bg-red-500")
})

it("renders random number of balls within maxRandomBalls", () => {
jest.spyOn(global.Math, "random").mockReturnValue(0.5)
render(<LoadingBalloonSpinner isRandom={true} maxRandomBalls={8} />)
const balls = screen.getAllByTestId("spinner-ball")
expect(balls.length).toBeGreaterThanOrEqual(1)
expect(balls.length).toBeLessThanOrEqual(8)
jest.spyOn(global.Math, "random").mockRestore()
})

it("applies animation delay to each ball", () => {
render(<LoadingBalloonSpinner numberOfBalls={3} />)
const balls = screen.getAllByTestId("spinner-ball")
expect(balls[0]).toHaveStyle("animation-delay: 0s")
expect(balls[1]).toHaveStyle("animation-delay: 0.15s")
expect(balls[2]).toHaveStyle("animation-delay: 0.3s")
})
})
43 changes: 43 additions & 0 deletions client/components/customized-ui/spinner/ball.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useEffect, useState } from "react"

interface LoadingBalloonSpinnerProps {
isRandom?: boolean
numberOfBalls?: number
maxRandomBalls?: number
color?: string
}

const LoadingBalloonSpinner: React.FC<LoadingBalloonSpinnerProps> = ({
isRandom = false,
numberOfBalls = 5,
maxRandomBalls = 5,
color = "bg-indigo-400",
}) => {
const [ballCount, setBallCount] = useState(numberOfBalls)

useEffect(() => {
if (isRandom) {
const randomCount = Math.floor(Math.random() * maxRandomBalls) + 1
setBallCount(randomCount)
} else {
setBallCount(numberOfBalls)
}
}, [isRandom, numberOfBalls, maxRandomBalls])

return (
<div className="flex items-center justify-center space-x-2">
{[...Array(ballCount)].map((_, index) => (
<div
key={index}
className={`h-4 w-4 animate-bounce rounded-full ${color}`}
style={{
animationDelay: `${index * 0.15}s`,
}}
data-testid="spinner-ball"
></div>
))}
</div>
)
}

export default LoadingBalloonSpinner
3 changes: 2 additions & 1 deletion client/modules/main/template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const MainPageTemplate = ({
const scopedT = useScopedI18n("index")

return (
<div className="relative mt-20 flex w-full flex-row items-center justify-center md:mt-16 md:h-screen ">
<div className="relative mt-20 flex w-full flex-row items-center justify-center md:mt-16 ">
<div className="relative z-30 h-fit w-full overflow-hidden md:mx-auto md:max-w-7xl md:p-4 ">
<motion.div
initial={{
Expand Down Expand Up @@ -92,6 +92,7 @@ const MainPageTemplate = ({
</Link>
)}
</div>

<div className="flex flex-row justify-center">
<UserCount numberOfMembers={count} />
</div>
Expand Down

0 comments on commit 56bbb75

Please sign in to comment.