feat: implement naming convention, deployment automation, and infrastructure updates

- Add comprehensive naming convention (provider-region-resource-env-purpose)
- Implement Terraform locals for centralized naming
- Update all Terraform resources to use new naming convention
- Create deployment automation framework (18 phase scripts)
- Add Azure setup scripts (provider registration, quota checks)
- Update deployment scripts config with naming functions
- Create complete deployment documentation (guide, steps, quick reference)
- Add frontend portal implementations (public and internal)
- Add UI component library (18 components)
- Enhance Entra VerifiedID integration with file utilities
- Add API client package for all services
- Create comprehensive documentation (naming, deployment, next steps)

Infrastructure:
- Resource groups, storage accounts with new naming
- Terraform configuration updates
- Outputs with naming convention examples

Deployment:
- Automated deployment scripts for all 15 phases
- State management and logging
- Error handling and validation

Documentation:
- Naming convention guide and implementation summary
- Complete deployment guide (296 steps)
- Next steps and quick start guides
- Azure prerequisites and setup completion docs

Note: ESLint warnings present - will be addressed in follow-up commit
This commit is contained in:
defiQUG
2025-11-12 08:22:51 -08:00
parent 9e46f3f316
commit 8649ad4124
136 changed files with 17251 additions and 147 deletions
+144
View File
@@ -0,0 +1,144 @@
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { cn } from '../lib/utils';
import { Alert, AlertDescription } from './Alert';
export type ToastVariant = 'default' | 'success' | 'error' | 'warning' | 'info';
export interface Toast {
id: string;
title?: string;
message: string;
variant: ToastVariant;
duration?: number;
}
interface ToastContextType {
toasts: Toast[];
addToast: (toast: Omit<Toast, 'id'>) => void;
removeToast: (id: string) => void;
success: (message: string, title?: string) => void;
error: (message: string, title?: string) => void;
warning: (message: string, title?: string) => void;
info: (message: string, title?: string) => void;
}
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export function useToast() {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within a ToastProvider');
}
return context;
}
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const removeToast = useCallback((id: string) => {
setToasts((prev) => prev.filter((toast) => toast.id !== id));
}, []);
const addToast = useCallback(
(toast: Omit<Toast, 'id'>) => {
const id = Math.random().toString(36).substring(2, 9);
const newToast: Toast = {
...toast,
id,
duration: toast.duration || 5000,
};
setToasts((prev) => [...prev, newToast]);
if (newToast.duration && newToast.duration > 0) {
setTimeout(() => {
removeToast(id);
}, newToast.duration);
}
},
[removeToast]
);
const success = useCallback(
(message: string, title?: string) => {
addToast({ message, title, variant: 'success' });
},
[addToast]
);
const error = useCallback(
(message: string, title?: string) => {
addToast({ message, title, variant: 'error' });
},
[addToast]
);
const warning = useCallback(
(message: string, title?: string) => {
addToast({ message, title, variant: 'warning' });
},
[addToast]
);
const info = useCallback(
(message: string, title?: string) => {
addToast({ message, title, variant: 'info' });
},
[addToast]
);
return (
<ToastContext.Provider value={{ toasts, addToast, removeToast, success, error, warning, info }}>
{children}
<ToastContainer toasts={toasts} removeToast={removeToast} />
</ToastContext.Provider>
);
}
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }) {
if (toasts.length === 0) return null;
return (
<div className="fixed top-4 right-4 z-50 flex flex-col gap-2 w-full max-w-sm">
{toasts.map((toast) => (
<ToastItem key={toast.id} toast={toast} onRemove={removeToast} />
))}
</div>
);
}
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }) {
const variantMap: Record<ToastVariant, { alert: 'default' | 'destructive' | 'success' | 'warning'; icon: string }> = {
default: { alert: 'default', icon: 'ℹ️' },
success: { alert: 'success', icon: '✓' },
error: { alert: 'destructive', icon: '✗' },
warning: { alert: 'warning', icon: '⚠' },
info: { alert: 'default', icon: 'ℹ️' },
};
const variant = variantMap[toast.variant];
return (
<Alert
variant={variant.alert}
className="animate-in slide-in-from-top-5 fade-in shadow-lg"
>
<div className="flex items-start justify-between">
<div className="flex-1">
{toast.title && (
<AlertDescription className="font-semibold mb-1">{toast.title}</AlertDescription>
)}
<AlertDescription>{toast.message}</AlertDescription>
</div>
<button
onClick={() => onRemove(toast.id)}
className="ml-4 text-gray-500 hover:text-gray-700 text-xl leading-none"
aria-label="Close"
>
×
</button>
</div>
</Alert>
);
}