UNPKG

@diagramers/admin

Version:

Diagramers Admin Template - React starter for admin dashboards.

311 lines (293 loc) 11 kB
import React, { useState, useRef } from 'react'; import { Row, Col, Card, Form, Button, Alert } from 'react-bootstrap'; import { useFormik } from 'formik'; import * as Yup from 'yup'; import { useDispatch } from 'react-redux'; import { useLocation } from 'react-router-dom'; import { settingsChangeColor } from 'settings/settingsSlice'; import { THEME_COLOR } from 'constants.js'; import CsLineIcons from 'cs-line-icons/CsLineIcons'; import configService from 'services/configService'; import './Setup.css'; const Setup = () => { const dispatch = useDispatch(); const location = useLocation(); const fileInputRef = useRef(null); const [logoPreview, setLogoPreview] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); // Available themes with preview colors const availableThemes = [ { key: THEME_COLOR.LightBlue, name: 'Light Blue', color: '#1ea8e7', description: 'Professional and clean blue theme' }, { key: THEME_COLOR.DarkBlue, name: 'Dark Blue', color: '#1ea8e7', description: 'Modern dark blue theme' }, { key: THEME_COLOR.LightRed, name: 'Light Red', color: '#cf2637', description: 'Energetic red theme' }, { key: THEME_COLOR.DarkRed, name: 'Dark Red', color: '#cf2637', description: 'Bold dark red theme' }, { key: THEME_COLOR.LightGreen, name: 'Light Green', color: '#439b38', description: 'Fresh green theme' }, { key: THEME_COLOR.DarkGreen, name: 'Dark Green', color: '#439b38', description: 'Natural dark green theme' }, { key: THEME_COLOR.LightPurple, name: 'Light Purple', color: '#6f42c1', description: 'Creative purple theme' }, { key: THEME_COLOR.DarkPurple, name: 'Dark Purple', color: '#6f42c1', description: 'Elegant dark purple theme' }, { key: THEME_COLOR.LightPink, name: 'Light Pink', color: '#e83e8c', description: 'Playful pink theme' }, { key: THEME_COLOR.DarkPink, name: 'Dark Pink', color: '#e83e8c', description: 'Vibrant dark pink theme' }, ]; const validationSchema = Yup.object().shape({ projectName: Yup.string() .min(2, 'Project name must be at least 2 characters') .max(50, 'Project name must be less than 50 characters') .required('Project name is required'), defaultTheme: Yup.string() .oneOf(Object.values(THEME_COLOR), 'Please select a valid theme') .required('Default theme is required'), }); const formik = useFormik({ initialValues: { projectName: '', defaultTheme: THEME_COLOR.LightBlue, }, validationSchema, onSubmit: async (values) => { setIsSubmitting(true); try { // Save project configuration using ConfigService const success = configService.completeSetup({ projectName: values.projectName, defaultTheme: values.defaultTheme, logo: logoPreview, }); if (success) { // Update theme dispatch(settingsChangeColor(values.defaultTheme)); // Update document title document.title = values.projectName; // Redirect to dashboard location.push('/'); } else { throw new Error('Failed to save configuration'); } } catch (error) { console.error('Setup failed:', error); alert('Failed to complete setup. Please try again.'); } finally { setIsSubmitting(false); } }, }); const handleLogoUpload = (event) => { const file = event.target.files[0]; if (file) { // Validate file type if (!file.type.startsWith('image/')) { alert('Please select an image file'); return; } // Validate file size (max 2MB) if (file.size > 2 * 1024 * 1024) { alert('Logo file size must be less than 2MB'); return; } const reader = new FileReader(); reader.onload = (e) => { setLogoPreview(e.target.result); }; reader.readAsDataURL(file); } }; const removeLogo = () => { setLogoPreview(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } }; return ( <div className="setup-page"> <div className="setup-container"> <Row className="justify-content-center"> <Col lg="8" xl="6"> <Card className="setup-card"> <Card.Body className="p-5"> {/* Header */} <div className="text-center mb-5"> <div className="setup-icon mb-3"> <CsLineIcons icon="settings" className="text-primary" size="48" /> </div> <h1 className="setup-title">Welcome to Your Admin Dashboard</h1> <p className="setup-subtitle text-muted"> Let's configure your project settings to get started </p> </div> <Form onSubmit={formik.handleSubmit}> {/* Project Name */} <Form.Group className="mb-4"> <Form.Label className="fw-bold">Project Name</Form.Label> <Form.Control type="text" name="projectName" placeholder="Enter your project name" value={formik.values.projectName} onChange={formik.handleChange} onBlur={formik.handleBlur} isInvalid={formik.touched.projectName && formik.errors.projectName} /> <Form.Control.Feedback type="invalid"> {formik.errors.projectName} </Form.Control.Feedback> <Form.Text className="text-muted"> This name will be displayed in the header and browser tab </Form.Text> </Form.Group> {/* Logo Upload */} <Form.Group className="mb-4"> <Form.Label className="fw-bold">Project Logo</Form.Label> <div className="logo-upload-area"> {logoPreview ? ( <div className="logo-preview-container"> <img src={logoPreview} alt="Logo preview" className="logo-preview" /> <Button variant="outline-danger" size="sm" onClick={removeLogo} className="remove-logo-btn" > <CsLineIcons icon="trash" /> </Button> </div> ) : ( <div className="logo-upload-placeholder" onClick={() => fileInputRef.current?.click()} > <CsLineIcons icon="upload" className="text-muted" size="32" /> <p className="mb-0 mt-2">Click to upload logo</p> <small className="text-muted">PNG, JPG, SVG (max 2MB)</small> </div> )} <input ref={fileInputRef} type="file" accept="image/*" onChange={handleLogoUpload} style={{ display: 'none' }} /> </div> <Form.Text className="text-muted"> Upload your project logo (recommended: 200x200px) </Form.Text> </Form.Group> {/* Theme Selection */} <Form.Group className="mb-5"> <Form.Label className="fw-bold">Default Theme</Form.Label> <div className="theme-grid"> {availableThemes.map((theme) => ( <div key={theme.key} className={`theme-option ${formik.values.defaultTheme === theme.key ? 'selected' : ''}`} onClick={() => formik.setFieldValue('defaultTheme', theme.key)} > <div className="theme-color-preview" style={{ backgroundColor: theme.color }} /> <div className="theme-info"> <h6 className="theme-name">{theme.name}</h6> <p className="theme-description">{theme.description}</p> </div> {formik.values.defaultTheme === theme.key && ( <div className="theme-selected"> <CsLineIcons icon="check" className="text-white" /> </div> )} </div> ))} </div> {formik.touched.defaultTheme && formik.errors.defaultTheme && ( <div className="text-danger mt-2">{formik.errors.defaultTheme}</div> )} </Form.Group> {/* Submit Button */} <div className="text-center"> <Button type="submit" size="lg" disabled={isSubmitting || !formik.isValid} className="setup-submit-btn" > {isSubmitting ? ( <> <span className="spinner-border spinner-border-sm me-2" /> Setting up... </> ) : ( <> <CsLineIcons icon="check" className="me-2" /> Complete Setup </> )} </Button> </div> </Form> {/* Info Alert */} <Alert variant="info" className="mt-4"> <CsLineIcons icon="info" className="me-2" /> <strong>Note:</strong> You can change these settings later from the admin panel. </Alert> </Card.Body> </Card> </Col> </Row> </div> </div> ); }; export default Setup;