Skip to content

Commit

Permalink
Merge pull request #8 from ad956/feature/membership-plans-ui
Browse files Browse the repository at this point in the history
♻️ Implement and refactor components for Membership Plans and UI
  • Loading branch information
ad956 authored Dec 25, 2024
2 parents 38a0ea0 + 2d967fb commit b96360d
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 9 deletions.
2 changes: 1 addition & 1 deletion client/src/pages/user/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
CreditStats,
GymMap,
GymMembership,
} from "./components/";
} from "./components";

const Dashboard = () => {
return (
Expand Down
5 changes: 0 additions & 5 deletions client/src/pages/user/Membership.jsx

This file was deleted.

21 changes: 21 additions & 0 deletions client/src/pages/user/MembershipPlans.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { PlansGrid } from "./components";
import { MEMBERSHIP_PLANS } from "@constants";

export default function MembershipPlans() {
return (
<div className="flex min-h-screen bg-gray-50">
<main className="flex-1 p-8">
<div className="mb-8">
<h2 className="text-xl font-semibold text-gray-900 mb-2">
Membership Plans
</h2>
<p className="text-gray-600">
Choose the perfect plan that fits your fitness goals
</p>
</div>
<PlansGrid plans={MEMBERSHIP_PLANS} />
</main>
</div>
);
}
53 changes: 53 additions & 0 deletions client/src/pages/user/components/MembershipPlans/PlanCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import { motion } from "framer-motion";
import { Card, CardBody, Button } from "@nextui-org/react";

export const PlanCard = ({ plan, isPopular }) => {
return (
<motion.div
whileHover={{ scale: 1.02 }}
transition={{ type: "spring", stiffness: 300 }}
>
<Card
className={`w-full ${
isPopular ? "border-2 border-blue-500" : "border border-gray-200"
}`}
shadow="sm"
>
<CardBody className="p-6">
{isPopular && (
<span className="absolute top-0 right-0 bg-gradient-to-r from-blue-500 to-indigo-500 text-white px-3 py-1 text-xs rounded-bl-lg">
Popular Choice
</span>
)}

<div className="mb-4">
<h3 className="text-xl font-semibold text-gray-900">
{plan.creditPoints} Credits Pack
</h3>
<p className="text-gray-600 text-sm mt-1">{plan.description}</p>
</div>

<div className="flex items-baseline mb-6">
<span className="text-3xl font-bold text-gray-900">
{plan.price.toFixed(2)}
</span>
<span className="text-gray-500 ml-2 text-sm">/package</span>
</div>

<Button
className={`w-full ${
isPopular
? "bg-gradient-to-r from-blue-500 to-indigo-500 text-white"
: "bg-gradient-to-r from-blue-50 to-indigo-50 text-blue-600"
}`}
size="lg"
onClick={() => alert(`Selected ${plan.creditPoints} credits plan`)}
>
Get Started
</Button>
</CardBody>
</Card>
</motion.div>
);
};
15 changes: 15 additions & 0 deletions client/src/pages/user/components/MembershipPlans/PlanFeatures.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { LuCheck } from "react-icons/lu";

export const PlanFeatures = ({ features }) => {
return (
<ul className="space-y-3">
{features.map((feature, index) => (
<li key={index} className="flex items-center gap-2">
<LuCheck size={16} className="text-primary-500" />
<span className="text-gray-600">{feature}</span>
</li>
))}
</ul>
);
};
38 changes: 38 additions & 0 deletions client/src/pages/user/components/MembershipPlans/PlansGrid.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";
import { motion } from "framer-motion";
import { PlanCard } from "./PlanCard";

export const PlansGrid = ({ plans }) => {
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};

const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 },
};

return (
<motion.div
variants={container}
initial="hidden"
animate="show"
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-7xl mx-auto px-4"
>
{plans.map((plan, index) => (
<motion.div key={plan.creditPoints} variants={item}>
<PlanCard
plan={plan}
isPopular={index === 2} // Making the third plan popular
/>
</motion.div>
))}
</motion.div>
);
};
3 changes: 3 additions & 0 deletions client/src/pages/user/components/MembershipPlans/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { PlansGrid } from "./PlansGrid";

export default PlansGrid;
2 changes: 2 additions & 0 deletions client/src/pages/user/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AnimatedQRCode from "./AnimatedQRCode";
import CreditStats from "./CreditStats";
import GymMap from "./GymMap";
import GymMembership from "./GymMembership";
import PlansGrid from "./MembershipPlans";
import ProfileSettings from "./Profile";
import QRCode from "./QRCode";

Expand All @@ -10,6 +11,7 @@ export {
CreditStats,
GymMap,
GymMembership,
PlansGrid,
ProfileSettings,
QRCode,
};
4 changes: 2 additions & 2 deletions client/src/pages/user/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Layout } from "@components";
import { Navigate, Route, Routes } from "react-router-dom";
import Dashboard from "./Dashboard";
import QRCodePage from "./QRCode";
import Membership from "./Membership";
import MembershipPlans from "./MembershipPlans";
import Transactions from "./Transactions";
import Profile from "./Profile";
import { PageNotFound } from "@components";
Expand All @@ -14,7 +14,7 @@ export default function UserLayout() {
<Route index element={<Navigate to="/user/dashboard" replace />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="qr-code" element={<QRCodePage />} />
<Route path="membership" element={<Membership />} />
<Route path="membership" element={<MembershipPlans />} />
<Route path="transactions" element={<Transactions />} />
<Route path="profile" element={<Profile />} />
{/* <Route path="*" element={<PageNotFound />} /> */}
Expand Down
35 changes: 34 additions & 1 deletion client/src/utils/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
const MEMBERSHIP_PLANS = [
{
creditPoints: 300,
price: 1500,
description: "Ideal for occasional gym visits.",
},
{
creditPoints: 900,
price: 3000,
description: "Great for regular gym-goers.",
},
{
creditPoints: 1800,
price: 5000,
description: "Perfect for fitness enthusiasts.",
},
{
creditPoints: 3600,
price: 8000,
description: "Ideal for frequent gym-goers.",
},
{
creditPoints: 4200,
price: 12000,
description: "Great value for fitness enthusiasts.",
},
{
creditPoints: 5000,
price: 15000,
description: "Ultimate plan for gym enthusiasts.",
},
];

const SERVER_URL =
import.meta.env.VITE_SERVER_URL || "http://localhost:3000/api/";

export { SERVER_URL };
export { MEMBERSHIP_PLANS, SERVER_URL };

0 comments on commit b96360d

Please sign in to comment.