В последнее время к нам в студию часто поступают запросы на разработку систем бронирования с возможностью управлять записями и справочниками. Особенно это актуально для B2C-сервисов вроде студий красоты и клиник, где нужно быстро и недорого собрать админ-панель, которая сразу включится в работу, без остановки процессов и долгого онбординга.

Многие из существующих систем-агрегаторов работают по линейному принципу. Это значит, что один мастер может за 1 единицу времени оказывать одну конкретную услугу. Из-за чего возникает проблема с групповыми записями, где один и тот же специалист может гибко участвовать в разных частях процедуры. 

В самих бронированиях также часто происходит изменения – отмены, переносы, замена одних услуг другими – которые часто влияют на график мастеров и требуют мгновенного обновления интерфейса. 

Поэтому компании все чаще обращаются за кастомными решениями. Но у самих разработчиков могут возникнуть вопросы: 

  • Какие фреймворки подходят для создания админ-панелей в системах бронирования?

  • Что делать, если типовые CRUD-генераторы не справляются с бизнес-логикой?

  • Можно ли сделать кастомный интерфейс без потери совместимости с остальной системой?

  • Как сократить время разработки и при этом сохранить гибкость?

Как Admiral обеспечивает кастомизацию без компромиссов

Большинство админок сегодня можно собирать на готовых фреймворках. И мы тоже раньше использовали популярные генераторы CRUD-интерфейсов, которые за 10 минут обещают готовые интерфейсы. Но сталкивались с тем, что у большинства из них – жестко определенная структура, в которой нельзя реализовать или настроить что-либо по своему усмотрению.

Нам нужно было больше свободы, поэтому мы пришли к созданию собственного фреймворка Admiral. И теперь используем его в 70% наших проектов. Это open-source решение, познакомиться с которым можно по ссылке: https://github.com/dev-family/admiral

Главные преимущества Admiral заключается в возможности:

  • Реализовать уникальные рабочие процессы, которые не вписываются в стандартную модель CRUD;

  • Создавать интерактивные дашборды с графиками, статистикой и другими виджетами, которые отображают важные данные в удобном формате.

Прочитать всю историю разработки Admiral можно тут.

Как это работает?

В основе Admiral лежит расширяемая архитектура, которая позволяет вам интегрировать собственные компоненты и логику. Это достигается за счёт гибкой системы маршрутизации и компонентов, а не генерации статических файлов с жёстко заданной структурой.

Так у нас получилось создать мощный и универсальный инструмент, который полностью адаптируется под бизнес-процессы наших клиентов.

Добавление кастомных страниц в Admiral

А теперь хочу поделиться собственным опытом кастомизации CRUD-интерфейсов с помощью Admiral на примере одного из недавних проектов. Нашим клиентом была сеть спа-салонов, где администраторам нужно было решать две основные задачи:

  • Создавать и редактировать записи;

  • Отслеживать загруженность мастеров через календарь.

В итоге мы разработали два удобных и эстетичных интерфейса, которые можно адаптировать под разные сценарии. Разберем процесс по шагам, чтобы смогли легко и быстро сделать то же самое для вашего проекта.

Управление записью

Начнем с разработки кастомной страницы создания/редактирования записи с кастомными компонентами. 

Создайте React-компонент, который будет отображать вашу кастомную страницу. В нём можно использовать как кастомные компоненты, так и стандартные компоненты Admiral, чтобы сохранить единый стиль и функциональность.

import React, { useCallback } from 'react'

import { Page, Form, Notification } from '@devfamily/admiral'

import { RecordSection, ClientSection, DiscountSection, PaymentSection } from './components'

import api from './api'

export enum RecordPageType {

    CREATE = 'create',

    EDIT = 'edit',

}

const RecordPage = ({ type }: { type: RecordPageType }) => {

    // Function to get default data if this is an edit page

    const fetchInitialData = useCallback(async () => {

        if (type === RecordPageType.EDIT) {

            let data = {}

            try {

            	// Connect API request to get record data

            } catch (err) {

                // Displaying an error notification

                Notification({

                    message: Error getting record: ${err?.message},

                    type: 'error',

                })

            }

            return Promise.resolve({

                data, 

                values: {},

            })

        } else {

            // Return empty data for the new record

            return Promise.resolve({

                data: {},  // Сan use default data

                values: {},

            })

        }

    }, [type, idRecord])

    // Function for submitting form data

    const onSubmit = useCallback(async (values) => {

        // Connect API request to create or edit record

    }, [])

    return (

        <Page title={type === RecordPageType.CREATE ? 'Add record' : Edit record}>

            <Form submitData={onSubmit} fetchInitialData={fetchInitialData}>

                {/* Include custom form sections as separate components */}

                <RecordSection />

                <ClientSection />

                <DiscountSection />

                <PaymentSection />

            </Form>

        </Page>

    )

}

export default RecordPage

В результате у вас получится вот такой интерфейс c использование кастомных компонентов.  

Теперь, когда у вас есть основной компонент  RecordPage, нужно создать файлы, которые будут использовать его в зависимости от типа операции (создание и редактирование). Эти файлы будут служить точками входа для маршрутизации Admiral.

Далее создайте следующие файлы в директории. Например, /pages/records/:

  • create.tsx  – страница для создания новой записи

import React from 'react'

import RecordPage, { RecordPageType } from '../RecordPage'

const CreateRecordPage = () => {

    return <RecordPage type={RecordPageType.CREATE} />

}

export default CreateRecordPage





[id].tsx – страница редактирования существующей записи ([id] в имени файла позволяет Admiral динамически определять маршрут):

import React from 'react'

import RecordPage, { RecordPageType } from '../RecordPage'

const EditRecordPage = () => {

    return <RecordPage type={RecordPageType.EDIT} />

}

export default EditRecordPage
  • index.tsx – базовая страница CRUD для отображения таблицы записей: 

import { CRUD } from '@/src/crud/records'

export default CRUD.IndexPage

В результате у нас получился полноценный CRUD со списком всех актуальных записей и кастомной страницей создания/редактирования записи. 

Создание календаря с записями

Получившаяся CRUD-таблица решает задачу хранения и поиска записей. Но для администраторов этого часто недостаточно, так как им важно следить за загрузкой всех мастеров: где есть свободные окна, какие записи перенесли, и какие услуги пересекаются. Поэтому мы добавили в нашу админ-панель кастомную страницу с календарём, где все бронирования сразу отображаются в общей сетке. 

В Admiral кастомные страницы подключаются так же, как и CRUD. Создайте отдельный React-компонент в директории /pages/main/, который отображает календарь с интерактивными элементами:

import React, { useEffect, useState } from 'react'

import { CalendarHeader, CalendarTable, CalendarRecordNote } from './ui'

import { TCalendarHeaderData, TGroupedServices, TCalendarHeaderData } from './ts'

import styles from './CalendarPage.module.scss'

const CelendarPage = () => {

    const [isLoading, setIsLoading] = useState<boolean>(false)

    const [timeSlots, setTimeSlots] = useState<string[]>([])

const [services, setServices] = useState<Array<TGroupedServices> | null>(null)

    const [calendarHeaderData, setCalendarHeaderData] = useState<Array<TCalendarHeaderData>>([])

    const [comment, setComment] = useState<string>('')

    const fetchCalendarData = async ({date}: {date: string}) => {

// Connect API request to get data

}

   useEffect(() => {

            fetchCalendarData({

                date: urlState.date || new Date()

            })

    }, [])

    return <Page title="Главная">

            <div className={styles.calendar_page}>

                <CalendarHeader />

                <CalendarRecordNote comment={comment} />

                <CalendarTable

                    isLoading={isLoading}

                    timeSlots={timeSlots}

                    services={services}

                    calendarHeaderData={calendarHeaderData}

                />

            </div>

</Page>

}

export default EditRecordPage

В результате администраторы могут работать с вот таким наглядным календарем. 

Интеграция в навигацию

После создания страниц необходимо добавить их в навигацию проекта, чтобы пользователи могли легко переходить на них. 

Для этого создайте файл с навигацией. Например, menu.tsx (если его ещё нет), и добавьте туда новые пункты навигации.

import React from 'react'

import { Menu, MenuItemLink } from '@devfamily/admiral'

import { FiUsers, FiUser, FiSettings } from 'react-icons/fi'


const CustomMenu = () => {

    return (

        <Menu>

        	<MenuItemLink icon="FiUsers" name="Main" to="/main" /> // navigate to custom page

     		<MenuItemLink icon="FiUser" name="Records" to="/records" /> // navigate to page with custom components

   <MenuItemLink icon="FiSettings" name="Services" to="/services" />

   <MenuItemLink icon="FiSettings" name="Masters" to="/masters" />

        </Menu>

    )

}

export default CustomMenu

Заключение 

Работая с Admiral над разными проектами, мы продолжаем убеждаться в его преимуществах: 

  • Подходит для проектов с нестандартной логикой – там, где типовые CRUD-генераторы быстро упираются в структурные ограничения, мы можем продолжать расширять интерфейс;

  • Предоставляет гибкость без лишнего кода – фреймворк обладает открытой архитектурой, в которую можно встроить что угодно: кастомные компоненты, бизнес-логику, календарные интерфейсы.

  • Обеспечивает скорость и масштабируемость – после быстрой сборки базового CRUD, вы сможете и дальше наращивать любые интерфейсы по мере роста проекта.

Благодаря Admiral команда сэкономит десятки часов на разработку и может более глубоко сосредоточиться на ценности проекта для бизнеса.

Комментарии (0)