npm package: @ragavkumarv/training-schedule-planner
Description: A reusable React component for displaying training schedules with calendar and list views
Author: Ragav Kumar V
Latest version: 1.1.0

# Training Schedule Component

A beautiful, reusable React component for displaying training schedules with calendar and list views. Built with TypeScript, Tailwind CSS, and Radix UI.

## Features

- 📅 **Calendar View**: Visual calendar layout showing training days and holidays
- 📋 **List View**: Clean list format with day numbers and dates
- 📊 **Statistics Cards**: Overview of total days, sessions, and holidays
- 🎨 **Beautiful UI**: Modern design with Tailwind CSS
- ♿ **Accessible**: Built with Radix UI primitives
- 📱 **Responsive**: Works on all screen sizes
- 🔧 **TypeScript**: Full type safety

## Installation

```bash
npm install @ragavkumarv/training-schedule-planner
```

### Peer Dependencies

Make sure you have these installed in your project:

```bash
npm install react react-dom date-fns lucide-react
```

## Quick Start

### 1. Create a New React App (if needed)

```bash
# Using Create React App
npx create-react-app my-training-app --template typescript
cd my-training-app

# Or using Next.js
npx create-next-app@latest my-training-app --typescript --tailwind --eslint
cd my-training-app

# Or using Vite
npm create vite@latest my-training-app -- --template react-ts
cd my-training-app
```

### 2. Install the Package

```bash
npm install @ragavkumarv/training-schedule-planner
```

### 3. Install Peer Dependencies

```bash
npm install react react-dom date-fns lucide-react react-day-picker
```

### 4. Setup Tailwind CSS (if not already installed)

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

## Complete Setup Guide

### Tailwind Configuration

Update your `tailwind.config.js`:

```js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    // Add this line to include the package components
    "./node_modules/@ragavkumarv/training-schedule-planner/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
    },
  },
  plugins: [],
}
```

### CSS Variables Setup

Add these CSS variables to your global CSS file (e.g., `src/index.css` or `app/globals.css`):

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}
```

## Usage Examples

### Basic Usage - Display Only

```tsx
import React from 'react';
import { TrainingSchedule, GeneratedSchedule } from '@ragavkumarv/training-schedule-planner';

const schedule: GeneratedSchedule = {
  trainingDays: [
    { date: new Date('2024-01-15'), dayNumber: 1 },
    { date: new Date('2024-01-16'), dayNumber: 2 },
    { date: new Date('2024-01-17'), dayNumber: 3 },
    // ... more training days
  ],
  startDate: new Date('2024-01-15'),
  endDate: new Date('2024-01-30'),
  totalDays: 10,
  skippedHolidays: [new Date('2024-01-26')], // Republic Day
};

function App() {
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">My Training Schedule</h1>
      <TrainingSchedule schedule={schedule} />
    </div>
  );
}

export default App;
```

### Complete App with Form

```tsx
import React, { useState } from 'react';
import { 
  TrainingSchedule, 
  TrainingForm, 
  GeneratedSchedule 
} from '@ragavkumarv/training-schedule-planner';

function App() {
  const [schedule, setSchedule] = useState<GeneratedSchedule | null>(null);

  const handleGenerateSchedule = (newSchedule: GeneratedSchedule) => {
    setSchedule(newSchedule);
  };

  return (
    <div className="min-h-screen bg-gray-50">
      <div className="container mx-auto px-4 py-8">
        <div className="text-center mb-8">
          <h1 className="text-4xl font-bold text-gray-900 mb-2">
            Training Schedule Planner
          </h1>
          <p className="text-lg text-gray-600">
            Plan your training sessions with holidays and custom schedules
          </p>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
          {/* Form Section */}
          <div className="space-y-6">
            <TrainingForm onGenerateSchedule={handleGenerateSchedule} />
          </div>

          {/* Schedule Display Section */}
          <div className="space-y-6">
            {schedule ? (
              <TrainingSchedule schedule={schedule} />
            ) : (
              <div className="flex items-center justify-center h-96 bg-white rounded-lg border border-gray-200">
                <div className="text-center">
                  <div className="text-6xl mb-4">📅</div>
                  <h3 className="text-xl font-semibold text-gray-700 mb-2">
                    No Schedule Generated
                  </h3>
                  <p className="text-gray-500">
                    Fill out the form to generate your training schedule
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;
```

### Next.js App Router Example

Create `app/training/page.tsx`:

```tsx
"use client";

import { useState } from "react";
import { 
  TrainingSchedule, 
  TrainingForm, 
  GeneratedSchedule 
} from "@ragavkumarv/training-schedule-planner";

export default function TrainingPage() {
  const [schedule, setSchedule] = useState<GeneratedSchedule | null>(null);

  const handleGenerateSchedule = (newSchedule: GeneratedSchedule) => {
    setSchedule(newSchedule);
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50">
      <div className="container mx-auto px-4 py-8">
        <div className="text-center mb-8">
          <h1 className="text-4xl font-bold text-gray-900 mb-2">
            Training Schedule Planner
          </h1>
          <p className="text-lg text-gray-600">
            Plan your training sessions with holidays and custom schedules
          </p>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
          <div className="space-y-6">
            <TrainingForm onGenerateSchedule={handleGenerateSchedule} />
          </div>

          <div className="space-y-6">
            {schedule ? (
              <TrainingSchedule schedule={schedule} />
            ) : (
              <div className="flex items-center justify-center h-96 bg-white/50 backdrop-blur-sm rounded-lg border border-gray-200">
                <div className="text-center">
                  <div className="text-6xl mb-4">📅</div>
                  <h3 className="text-xl font-semibold text-gray-700 mb-2">
                    No Schedule Generated
                  </h3>
                  <p className="text-gray-500">
                    Fill out the form to generate your training schedule
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

## Tailwind CSS Setup

This component requires Tailwind CSS. Add these to your `tailwind.config.js`:

```js
module.exports = {
  content: [
    // ... your existing content paths
    "./node_modules/@ragavkumarv/training-schedule-planner/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
    },
  },
  plugins: [],
}
```

And add these CSS variables to your global CSS:

```css
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}
```

## Component API

### TrainingForm

The `TrainingForm` component provides a complete form interface for creating training schedules.

**Props:**
- `onGenerateSchedule: (schedule: GeneratedSchedule) => void` - Callback function called when a schedule is generated

**Features:**
- Date picker for start date
- Number input for training days
- Weekday selection checkboxes
- Holiday and break date range picker
- Form validation

### TrainingSchedule

The `TrainingSchedule` component displays generated training schedules in multiple views.

**Props:**
- `schedule: GeneratedSchedule` - The schedule object to display

**Features:**
- Calendar view with visual indicators
- List view with detailed information
- Statistics cards showing totals
- Holiday highlighting
- Responsive design

## Advanced Usage

### Custom Styling

You can customize the appearance by overriding CSS variables:

```css
:root {
  --primary: 220 14.3% 95.9%; /* Custom primary color */
  --primary-foreground: 220.9 39.3% 11%;
  --radius: 0.75rem; /* Custom border radius */
}
```

### Using Individual Components

You can also import and use individual UI components:

```tsx
import { 
  Card, 
  CardContent, 
  CardHeader, 
  CardTitle,
  Button,
  Calendar 
} from '@ragavkumarv/training-schedule-planner';

function MyCustomComponent() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Custom Card</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Click me</Button>
      </CardContent>
    </Card>
  );
}
```

### Using the Schedule Generator

You can use the schedule generation logic independently:

```tsx
import { 
  generateSchedule, 
  TrainingConfig, 
  GeneratedSchedule 
} from '@ragavkumarv/training-schedule-planner';

const config: TrainingConfig = {
  startDate: new Date('2024-01-15'),
  numberOfDays: 20,
  holidays: [
    { id: '1', date: new Date('2024-01-26') }
  ],
  dateRanges: [],
  weekdays: {
    sun: false,
    mon: true,
    tue: true,
    wed: true,
    thu: true,
    fri: true,
    sat: false
  }
};

const schedule: GeneratedSchedule = generateSchedule(config);
```

## Troubleshooting

### Common Issues

**1. Styles not appearing:**
- Ensure Tailwind CSS is properly configured
- Check that the package path is included in your `tailwind.config.js`
- Verify CSS variables are defined in your global CSS

**2. TypeScript errors:**
- Make sure all peer dependencies are installed
- Check that your TypeScript version is compatible

**3. Calendar not working:**
- Ensure `react-day-picker` is installed as a peer dependency
- Check that date-fns is properly installed

**4. Build errors:**
- Verify all peer dependencies are installed
- Check for version conflicts in your package.json

### Getting Help

If you encounter issues:
1. Check the [GitHub Issues](https://github.com/ragavkumarv/training-schedule-planner/issues)
2. Review the troubleshooting section above
3. Ensure all setup steps are completed correctly

## Framework-Specific Notes

### Next.js
- Use `"use client"` directive for components that use state
- Ensure Tailwind is configured in `tailwind.config.js`
- Add CSS variables to `app/globals.css`

### Create React App
- Install Tailwind CSS separately if not included
- Add CSS variables to `src/index.css`
- No additional configuration needed

### Vite
- Install Tailwind CSS plugin
- Configure PostCSS if needed
- Add CSS variables to your main CSS file

## Types

### GeneratedSchedule

```tsx
interface GeneratedSchedule {
  trainingDays: TrainingDay[];
  startDate: Date;
  endDate: Date;
  totalDays: number;
  skippedHolidays: Date[];
}
```

### TrainingDay

```tsx
interface TrainingDay {
  date: Date;
  dayNumber: number;
}
```

## Customization

The component uses Tailwind CSS classes and can be customized by:

1. **CSS Variables**: Modify the color scheme using CSS custom properties
2. **Tailwind Classes**: Override classes using Tailwind's utility classes
3. **Component Props**: Pass custom className props to the main component

## Development

To build the package:

```bash
npm run build
```

To watch for changes during development:

```bash
npm run dev
```

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.