@snapdragonsnursery/react-components
v1.19.7
Published
A collection of reusable React components for Snapdragons Nursery applications.
Readme
@snapdragonsnursery/react-components
A collection of reusable React components for Snapdragons Nursery applications.
Components
- ChildSearchModal: Advanced child search and selection component with filtering, pagination, and multi-select capabilities
- ChildSearchFilters: Advanced filtering component with date range picker, status, site, and age filters (includes Apply button for better UX)
- EmployeeSelect: Lightweight, searchable employee selector with grouping and optional avatars
- EmployeeSearchModal: Advanced employee search with server-side filtering, pagination, and complex filters
- DateRangePicker: Shadcn-style date range picker component (supports optional presets)
- DatePicker: Shadcn-style single date picker component
- Calendar: Official shadcn calendar component
- Popover: Official shadcn popover component
- AuthButtons: Authentication buttons for MSAL integration
- ThemeToggle: Dark/light theme toggle component
- LandingPage: Landing page component with authentication
- SoftWarningAlert: Soft-styled alert for non-blocking warnings with optional action
Installation
npm install @snapdragonsnursery/react-componentsQuick Start
import { ChildSearchModal } from '@snapdragonsnursery/react-components';
function MyComponent() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<ChildSearchModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSelect={(child) => console.log('Selected:', child)}
title="Search for a Child"
/>
);
}EmployeeSelect Example
import { EmployeeSelect } from '@snapdragonsnursery/react-components';
function MyComponent() {
const [selectedEntraId, setSelectedEntraId] = useState();
const employees = [
{
entra_id: '123-456',
full_name: 'Jane Smith',
site_name: 'Main Office',
role_name: 'Teacher',
employee_id: 'EMP001',
email: '[email protected]',
employee_status: 'Active'
},
// ... more employees
];
return (
<EmployeeSelect
value={selectedEntraId}
onChange={setSelectedEntraId}
items={employees}
groupBy="site"
showAvatar
showSiteName
placeholder="Select an employee..."
/>
);
}EmployeeSelect vs EmployeeSearchModal:
- EmployeeSelect: Use for simple dropdown selection with pre-loaded employee data. Supports grouping by site/role, optional avatars, and built-in client-side search. Perfect for forms with limited employee lists.
- EmployeeSearchModal: Use for advanced search scenarios requiring server-side filtering, pagination, complex multi-criteria filters, and multi-select. Ideal for large employee databases.
SoftWarningAlert Example
import { SoftWarningAlert } from '@snapdragonsnursery/react-components';
import { AlertTriangle } from 'lucide-react';
function Notice() {
return (
<SoftWarningAlert
icon={AlertTriangle}
title="Unsubmitted claims"
description="You have 3 unsubmitted mileage claims. Create a report to submit."
actionLabel="Create report"
onAction={() => console.log('clicked')}
/>
);
}Shadcn Components
This package includes official shadcn components with proper styling. The components use shadcn CSS variables, so make sure your consuming project has the shadcn CSS variables defined in your CSS file.
For Consuming Projects
- Ensure your project has shadcn CSS variables in your main CSS file (like
src/index.css):
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--accent: 210 40% 96%;
--accent-foreground: 222.2 84% 4.9%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
}- Update your Tailwind config to include the react-components package:
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/@snapdragonsnursery/react-components/src/**/*.{js,jsx}'
],
// ... rest of your config
}- Install tailwindcss-animate for proper animations:
npm install tailwindcss-animateDate Range Picker Example
import { DateRangePicker } from '@snapdragonsnursery/react-components';
function MyComponent() {
const [selectedRange, setSelectedRange] = useState(null);
const handleDateRangeChange = (range) => {
// Only update your filters when both dates are selected
if (range?.from && range?.to) {
// Both dates selected - update your filters
setFilters(prev => ({
...prev,
dobFrom: range.from.toISOString().split('T')[0],
dobTo: range.to.toISOString().split('T')[0],
}));
} else if (!range?.from && !range?.to) {
// Range cleared - clear your filters
setFilters(prev => ({
...prev,
dobFrom: '',
dobTo: '',
}));
}
// Don't update filters when only first date is selected
setSelectedRange(range);
};
return (
<>
<DateRangePicker
selectedRange={selectedRange}
onSelect={handleDateRangeChange}
placeholder="Select a date range"
numberOfMonths={2}
/>
{/* With presets */}
<DateRangePicker
selectedRange={selectedRange}
onSelect={handleDateRangeChange}
presetsEnabled
presets={[
{ key: 'thisWeek', label: 'This week', getRange: () => ({ from: startOfWeek(new Date(), { weekStartsOn: 1 }), to: new Date() }) },
{ key: 'lastWeek', label: 'Last week', getRange: () => { const ref = subWeeks(new Date(), 1); return { from: startOfWeek(ref, { weekStartsOn: 1 }), to: endOfWeek(ref, { weekStartsOn: 1 }) } } },
{ key: 'thisMonth', label: 'This month', getRange: () => ({ from: startOfMonth(new Date()), to: new Date() }) },
{ key: 'lastMonth', label: 'Last month', getRange: () => { const ref = subMonths(new Date(), 1); return { from: startOfMonth(ref), to: endOfMonth(ref) } } },
{ key: 'thisYear', label: 'This year', getRange: () => ({ from: startOfYear(new Date()), to: new Date() }) },
{ key: 'lastYear', label: 'Last year', getRange: () => { const ref = subYears(new Date(), 1); return { from: startOfYear(ref), to: endOfYear(ref) } } },
]}
/>
</>
);
}Important: The DateRangePicker now maintains its own internal state and only calls onSelect when both dates are selected or when the range is cleared. This prevents premature re-renders and keeps the calendar open until the user completes their selection. The ChildSearchFilters component includes an "Apply Filters" button that only triggers searches when clicked, providing better user control.
Apply Button Functionality
The ChildSearchFilters component now includes an "Apply Filters" button that provides better user control:
- Local State: Filter changes are stored locally until applied
- Visual Feedback: Shows "You have unsaved filter changes" when filters are modified
- Apply Button: Only triggers search when clicked
- Cancel Button: Reverts changes without applying
- Better UX: Users can configure multiple filters before searching
<ChildSearchFilters
filters={filters}
onFiltersChange={setFilters}
onApplyFilters={setFilters} // New callback for applying filters
sites={sites}
// ... other props
/>Environment Variables
Set this environment variable in your application:
VITE_APIM_SCOPE=api://your-apim-app-id/.defaultDocumentation
- ChildSearchModal Documentation
- ChildSearchModal README
- EmployeeSelect Documentation
- Release Guide
- SoftWarningAlert
🚀 Publishing New Versions
Quick Release (Recommended)
# Patch release (bug fixes) - 1.1.0 → 1.1.1
npm run release
# Minor release (new features) - 1.1.0 → 1.2.0
npm run release:minor
# Major release (breaking changes) - 1.1.0 → 2.0.0
npm run release:majorGitHub Actions (Web Interface)
- Go to GitHub Actions
- Click "Publish Package"
- Click "Run workflow"
- Select version type (patch/minor/major)
- Click "Run workflow"
Manual Commands
# Just bump version
npm run version:patch
npm run version:minor
npm run version:major
# Bump and publish
npm run publish:patch
npm run publish:minor
npm run publish:majorPre-release Versions (Beta)
# Create beta version
npm run publish:prepatch
npm run publish:preminor
npm run publish:premajor
# Install beta in consuming apps
npm install @snapdragonsnursery/react-components@betaVersion Types
| Type | Example | Use Case | |------|---------|----------| | patch | 1.1.0 → 1.1.1 | Bug fixes, documentation | | minor | 1.1.0 → 1.2.0 | New features, backward compatible | | major | 1.1.0 → 2.0.0 | Breaking changes | | prepatch | 1.1.0 → 1.1.1-0 | Beta patch release | | preminor | 1.1.0 → 1.2.0-0 | Beta minor release | | premajor | 1.1.0 → 2.0.0-0 | Beta major release |
Release Checklist
Before releasing:
- [ ] All changes committed and pushed
- [ ] Tests pass (if configured)
- [ ] Documentation updated
- [ ] Version type selected (patch/minor/major)
- [ ] NPM token configured (for GitHub Actions)
Troubleshooting
Common Issues
"Working directory not clean"
git add .
git commit -m "Prepare for release""Not on main branch"
git checkout main
git pull origin main"NPM authentication failed"
- Check GitHub Secrets → NPM_TOKEN
- Verify token has publish permissions
"Version already exists"
npm run release:minor # Use different version typeSupport
For issues with components or release process:
- Check component documentation
- Review Release Guide
- Check GitHub Actions logs
- Contact the development team
Contributing
- Make changes in feature branch
- Test locally
- Create pull request
- Merge to main
- Release using one of the methods above
Current Version: 1.1.0
Last Updated: January 2024
