From cb640957da0fc62cd78b44f596ddddd950923074 Mon Sep 17 00:00:00 2001 From: Aleksey Zverev Date: Tue, 30 Jan 2024 22:22:29 +0200 Subject: [PATCH] Add filter to the stock page --- web/internal/api/api.go | 61 ++- web/internal/controller/dictionary.go | 8 + web/internal/controller/stock.go | 10 +- web/internal/service/dictionary/dictionary.go | 19 + web/internal/service/stock/stock.go | 12 +- web/internal/storage/builder/builder.go | 8 + web/internal/storage/builder/stock.go | 90 ++++ web/internal/storage/builder/stock_test.go | 20 + web/internal/storage/marketplace.go | 20 + web/internal/storage/stock.go | 26 +- web/openapi/openapi.yml | 57 +++ website/package-lock.json | 447 +++++++++--------- website/package.json | 6 +- website/src/client/index.ts | 2 + website/src/client/models/Dictionaries.ts | 11 + website/src/client/models/Marketplace.ts | 11 + .../client/services/DictionariesService.ts | 13 + website/src/client/services/StocksService.ts | 12 + website/src/components/JoyDatePicker.tsx | 7 +- website/src/components/PickerWithJoyField.tsx | 210 ++++++++ website/src/context/actions/index.ts | 33 +- website/src/context/index.tsx | 44 +- website/src/layouts/auth/index.tsx | 3 +- website/src/layouts/stock/index.tsx | 160 +++++-- website/src/layouts/test/index.tsx | 65 ++- website/src/layouts/test/style.css | 3 + 26 files changed, 1056 insertions(+), 302 deletions(-) create mode 100644 web/internal/storage/builder/builder.go create mode 100644 web/internal/storage/builder/stock.go create mode 100644 web/internal/storage/builder/stock_test.go create mode 100644 web/internal/storage/marketplace.go create mode 100644 website/src/client/models/Dictionaries.ts create mode 100644 website/src/client/models/Marketplace.ts create mode 100644 website/src/components/PickerWithJoyField.tsx create mode 100644 website/src/layouts/test/style.css diff --git a/web/internal/api/api.go b/web/internal/api/api.go index a21677e..c6c955d 100644 --- a/web/internal/api/api.go +++ b/web/internal/api/api.go @@ -71,6 +71,11 @@ type DictPositions struct { Items []DictPosition `json:"items"` } +// Dictionaries defines model for Dictionaries. +type Dictionaries struct { + Marketplaces []Marketplace `json:"marketplaces"` +} + // ErrorData defines model for ErrorData. type ErrorData struct { Description string `json:"description"` @@ -83,6 +88,13 @@ type LoginInfo struct { Password string `json:"password"` } +// Marketplace defines model for Marketplace. +type Marketplace struct { + Code string `json:"code"` + Name string `json:"name"` + ShortName string `json:"shortName"` +} + // Order defines model for Order. type Order struct { Balance int32 `json:"balance"` @@ -324,12 +336,16 @@ type GetStocksWithPagesParams struct { Date openapi_types.Date `form:"date" json:"date"` Limit int `form:"limit" json:"limit"` Offset int `form:"offset" json:"offset"` + Source *[]string `form:"source,omitempty" json:"source,omitempty"` + Filter *string `form:"filter,omitempty" json:"filter,omitempty"` } // ExportStocksParams defines parameters for ExportStocks. type ExportStocksParams struct { // Date Дата (YYYY-MM-DD) - Date openapi_types.Date `form:"date" json:"date"` + Date openapi_types.Date `form:"date" json:"date"` + Source *[]string `form:"source,omitempty" json:"source,omitempty"` + Filter *string `form:"filter,omitempty" json:"filter,omitempty"` } // LoginJSONRequestBody defines body for Login for application/json ContentType. @@ -359,6 +375,9 @@ type ServerInterface interface { // (GET /auth/refresh) Refresh(ctx echo.Context) error + // (GET /dictionaries) + GetDictionaries(ctx echo.Context) error + // (GET /dictionaries/clusters) GetClusters(ctx echo.Context, params GetClustersParams) error @@ -442,6 +461,17 @@ func (w *ServerInterfaceWrapper) Refresh(ctx echo.Context) error { return err } +// GetDictionaries converts echo context to params. +func (w *ServerInterfaceWrapper) GetDictionaries(ctx echo.Context) error { + var err error + + ctx.Set(ApiKeyAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetDictionaries(ctx) + return err +} + // GetClusters converts echo context to params. func (w *ServerInterfaceWrapper) GetClusters(ctx echo.Context) error { var err error @@ -755,6 +785,20 @@ func (w *ServerInterfaceWrapper) GetStocksWithPages(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter offset: %s", err)) } + // ------------- Optional query parameter "source" ------------- + + err = runtime.BindQueryParameter("form", true, false, "source", ctx.QueryParams(), ¶ms.Source) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter source: %s", err)) + } + + // ------------- Optional query parameter "filter" ------------- + + err = runtime.BindQueryParameter("form", true, false, "filter", ctx.QueryParams(), ¶ms.Filter) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter filter: %s", err)) + } + // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetStocksWithPages(ctx, params) return err @@ -775,6 +819,20 @@ func (w *ServerInterfaceWrapper) ExportStocks(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter date: %s", err)) } + // ------------- Optional query parameter "source" ------------- + + err = runtime.BindQueryParameter("form", true, false, "source", ctx.QueryParams(), ¶ms.Source) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter source: %s", err)) + } + + // ------------- Optional query parameter "filter" ------------- + + err = runtime.BindQueryParameter("form", true, false, "filter", ctx.QueryParams(), ¶ms.Filter) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter filter: %s", err)) + } + // Invoke the callback with all the unmarshaled arguments err = w.Handler.ExportStocks(ctx, params) return err @@ -829,6 +887,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/auth/login", wrapper.Login) router.GET(baseURL+"/auth/profile", wrapper.Profile) router.GET(baseURL+"/auth/refresh", wrapper.Refresh) + router.GET(baseURL+"/dictionaries", wrapper.GetDictionaries) router.GET(baseURL+"/dictionaries/clusters", wrapper.GetClusters) router.POST(baseURL+"/dictionaries/positions", wrapper.GetPositions) router.GET(baseURL+"/dictionaries/warehouses", wrapper.GetWarehouses) diff --git a/web/internal/controller/dictionary.go b/web/internal/controller/dictionary.go index 05d5717..655a5a6 100644 --- a/web/internal/controller/dictionary.go +++ b/web/internal/controller/dictionary.go @@ -43,6 +43,14 @@ func (c *Controller) UpdateWarehouse(ctx echo.Context) error { return ctx.JSON(http.StatusOK, r) } +func (c *Controller) GetDictionaries(ctx echo.Context) error { + dict, err := c.dictService.GetDictionary(ctx.Request().Context()) + if err != nil { + return err + } + return ctx.JSON(http.StatusOK, dict) +} + func (c *Controller) GetClusters(ctx echo.Context, params api.GetClustersParams) error { values, err := c.store.GetClusters(ctx.Request().Context(), params.Filter) if err != nil { diff --git a/web/internal/controller/stock.go b/web/internal/controller/stock.go index a111d85..ab2bcce 100644 --- a/web/internal/controller/stock.go +++ b/web/internal/controller/stock.go @@ -1,6 +1,7 @@ package controller import ( + "context" "errors" "fmt" "github.com/labstack/echo/v4" @@ -29,11 +30,12 @@ type AuthService interface { } type IStockService interface { - GetStocks(stockDate time.Time, limit, offset int) (*api.StocksFull, error) - ExportStocks(writer http.ResponseWriter, stockDate time.Time) error + GetStocks(stockDate time.Time, limit, offset int, source *[]string, filter *string) (*api.StocksFull, error) + ExportStocks(writer http.ResponseWriter, stockDate time.Time, source *[]string, filter *string) error } type DictionaryService interface { + GetDictionary(ctx context.Context) (*api.Dictionaries, error) GetPositions(offset int32, limit int32, source []string, filter *string) (*api.DictPositions, error) ExportWarehouses(writer http.ResponseWriter, source []string, code *string, cluster *string) error GetWarehouses(offset int32, limit int32, source []string, code *string, cluster *string) (*api.Warehouses, error) @@ -69,7 +71,7 @@ func (c *Controller) ExportStocks(ctx echo.Context, params api.ExportStocksParam ctx.Response().Header().Set(echo.HeaderContentType, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") ctx.Response().Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) ctx.Response().WriteHeader(http.StatusOK) - return c.stockService.ExportStocks(ctx.Response().Writer, params.Date.Time) + return c.stockService.ExportStocks(ctx.Response().Writer, params.Date.Time, params.Source, params.Filter) } @@ -91,7 +93,7 @@ func (c *Controller) GetStocks(ctx echo.Context, date string) error { } func (c *Controller) GetStocksWithPages(ctx echo.Context, params api.GetStocksWithPagesParams) error { - stocks, err := c.stockService.GetStocks(params.Date.Time, params.Limit, params.Offset) + stocks, err := c.stockService.GetStocks(params.Date.Time, params.Limit, params.Offset, params.Source, params.Filter) if err != nil { return err } diff --git a/web/internal/service/dictionary/dictionary.go b/web/internal/service/dictionary/dictionary.go index 45b0ffe..53695a6 100644 --- a/web/internal/service/dictionary/dictionary.go +++ b/web/internal/service/dictionary/dictionary.go @@ -7,6 +7,7 @@ import ( ) type IDictionaryRepository interface { + GetMarketplaces(ctx context.Context) (*[]storage.Marketplace, error) GetClusters(context context.Context, filter *string) (*[]string, error) GetPositions(offset int32, limit int32, source []string, filter *string) (*[]storage.Position, error) GetWarehousesWithoutPages(source []string, code *string, cluster *string) (*[]storage.Warehouse, error) @@ -23,6 +24,24 @@ func NewDictionaryService(repository IDictionaryRepository) *DictionaryService { } } +func (s *DictionaryService) GetDictionary(ctx context.Context) (*api.Dictionaries, error) { + marketplaces, err := s.repository.GetMarketplaces(ctx) + if err != nil { + return nil, err + } + mp := make([]api.Marketplace, len(*marketplaces)) + for i, item := range *marketplaces { + mp[i] = api.Marketplace{ + Code: item.Code, + Name: item.Name, + ShortName: item.ShortName, + } + } + return &api.Dictionaries{ + Marketplaces: mp, + }, nil +} + func (s *DictionaryService) GetPositions(offset int32, limit int32, source []string, filter *string) (*api.DictPositions, error) { positions, err := s.repository.GetPositions(offset, limit, source, filter) if err != nil { diff --git a/web/internal/service/stock/stock.go b/web/internal/service/stock/stock.go index 6e65dc5..3b68567 100644 --- a/web/internal/service/stock/stock.go +++ b/web/internal/service/stock/stock.go @@ -61,8 +61,8 @@ var header []service.ExcelHeaderColumn = []service.ExcelHeaderColumn{ } type IStockRepository interface { - GetSticksWithPage(stockDate time.Time, limit, offset int) (*[]storage.StockFull, error) - GetStocks(stockDate time.Time) (*[]storage.StockFull, error) + GetSticksWithPage(stockDate time.Time, limit, offset int, source *[]string, filter *string) (*[]storage.StockFull, error) + GetStocks(stockDate time.Time, source *[]string, filter *string) (*[]storage.StockFull, error) } type Service struct { @@ -75,8 +75,8 @@ func NewStockService(repository IStockRepository) *Service { } } -func (s *Service) ExportStocks(writer http.ResponseWriter, stockDate time.Time) error { - stocks, err := s.repository.GetStocks(stockDate) +func (s *Service) ExportStocks(writer http.ResponseWriter, stockDate time.Time, source *[]string, filter *string) error { + stocks, err := s.repository.GetStocks(stockDate, source, filter) if err != nil { return err } @@ -84,8 +84,8 @@ func (s *Service) ExportStocks(writer http.ResponseWriter, stockDate time.Time) } // Get stocks with the pagginations -func (s *Service) GetStocks(stockDate time.Time, limit, offset int) (*api.StocksFull, error) { - stocks, err := s.repository.GetSticksWithPage(stockDate, limit, offset) +func (s *Service) GetStocks(stockDate time.Time, limit, offset int, source *[]string, filter *string) (*api.StocksFull, error) { + stocks, err := s.repository.GetSticksWithPage(stockDate, limit, offset, source, filter) if err != nil { return nil, err } diff --git a/web/internal/storage/builder/builder.go b/web/internal/storage/builder/builder.go new file mode 100644 index 0000000..073815a --- /dev/null +++ b/web/internal/storage/builder/builder.go @@ -0,0 +1,8 @@ +package builder + +type SQLBuilder struct { +} + +func (s *SQLBuilder) Build() { + +} diff --git a/web/internal/storage/builder/stock.go b/web/internal/storage/builder/stock.go new file mode 100644 index 0000000..d6c2e26 --- /dev/null +++ b/web/internal/storage/builder/stock.go @@ -0,0 +1,90 @@ +package builder + +import ( + "fmt" + "time" +) + +const sql_stocks_base = `select s.stock_date, s.source, o.name org, s.supplier_article, s.barcode, s.external_code sku, + s.name, s.brand, s.warehouse, s.quantity, s.price, s.price_with_discount + from bl.stock s +inner join ml.owner o on o.code = s.owner_code +where stock_date = @stock_date` +const sql_stock_where_source = ` and source in @source` +const sql_stock_where_filter = ` and (s.supplier_article like @filter or s.barcode like @filter or s.external_code like @filter or s.name like @filter or s.brand like @filter or s.warehouse like @filter)` + +const sql_wrapper = `with t as (%s) +select +stock_date, +source, +org, +supplier_article, +barcode, +sku, +name, +brand, +warehouse, +quantity, +price, +price_with_discount, +(select count(1) from t) total +from t +limit @limit offset @offset` + +type StockSQLBuilder struct { + sources *[]string + filter *string + stockSate time.Time + limit *int + offset *int +} + +func NewStockSQLBuilder(stockDate time.Time) *StockSQLBuilder { + return &StockSQLBuilder{ + stockSate: stockDate, + } +} + +func (s *StockSQLBuilder) Sources(sources *[]string) *StockSQLBuilder { + s.sources = sources + return s +} + +func (s *StockSQLBuilder) Filter(filter *string) *StockSQLBuilder { + s.filter = filter + return s +} + +func (s *StockSQLBuilder) Limit(limit *int) *StockSQLBuilder { + s.limit = limit + return s +} + +func (s *StockSQLBuilder) Offset(offset *int) *StockSQLBuilder { + s.offset = offset + return s +} + +func (s *StockSQLBuilder) Build() (string, map[string]interface{}) { + var vars = make(map[string]interface{}) + vars["stock_date"] = s.stockSate + query := sql_stocks_base + if s.sources != nil && len(*s.sources) != 0 { + vars["source"] = *s.sources + } else { + vars["source"] = []string{} + } + query += sql_stock_where_source + if s.filter != nil && len(*s.filter) != 0 { + str := *s.filter + vars["filter"] = "%" + str + "%" + query += sql_stock_where_filter + } + if s.limit != nil || s.offset != nil { + query = fmt.Sprintf(sql_wrapper, query) + vars["limit"] = *s.limit + vars["offset"] = *s.offset + } + + return query, vars +} diff --git a/web/internal/storage/builder/stock_test.go b/web/internal/storage/builder/stock_test.go new file mode 100644 index 0000000..72c8ea6 --- /dev/null +++ b/web/internal/storage/builder/stock_test.go @@ -0,0 +1,20 @@ +package builder + +import ( + "testing" + "time" +) + +func TestStockBuilder(t *testing.T) { + builder := NewStockSQLBuilder(time.Now()) + + builder.Sources(&[]string{"1", "2"}) + limit := 10 + offset := 20 + builder.Limit(&limit) + builder.Offset(&offset) + filter := "filter" + builder.Filter(&filter) + sql, _ := builder.Build() + print(sql) +} diff --git a/web/internal/storage/marketplace.go b/web/internal/storage/marketplace.go new file mode 100644 index 0000000..5401400 --- /dev/null +++ b/web/internal/storage/marketplace.go @@ -0,0 +1,20 @@ +package storage + +import "context" + +type Marketplace struct { + Code string `gorm:"column:code"` + Name string `gorm:"column:name"` + ShortName string `gorm:"column:short_name"` +} + +func (s *Storage) GetMarketplaces(ctx context.Context) (*[]Marketplace, error) { + var marketplaces []Marketplace + tx := s.db.WithContext(ctx).Table("ml.marketplace").Scan(&marketplaces) + if tx.Error != nil { + return nil, tx.Error + } + + return &marketplaces, nil + +} diff --git a/web/internal/storage/stock.go b/web/internal/storage/stock.go index fb0a0bd..5047fbd 100644 --- a/web/internal/storage/stock.go +++ b/web/internal/storage/stock.go @@ -1,7 +1,7 @@ package storage import ( - sql2 "database/sql" + "github.com/yoda/web/internal/storage/builder" "time" ) @@ -50,7 +50,7 @@ const sql_stocks_base = `select s.stock_date, s.source, o.name org, s.supplier_a s.name, s.brand, s.warehouse, s.quantity, s.price, s.price_with_discount from bl.stock s inner join ml.owner o on o.code = s.owner_code -where stock_date =@stock_date` +where stock_date =@stock_date and source in @source` const sql_stocks = `with t as (` + sql_stocks_base + `) select @@ -67,27 +67,27 @@ quantity, price, price_with_discount, (select count(1) from t) total -from t +from t limit @limit offset @offset` -func (s *Storage) GetSticksWithPage(stockDate time.Time, limit, offset int) (*[]StockFull, error) { +func (s *Storage) GetSticksWithPage(stockDate time.Time, limit, offset int, source *[]string, filter *string) (*[]StockFull, error) { var stocks []StockFull - err := s.db.Raw(sql_stocks, - sql2.Named("stock_date", stockDate), - sql2.Named("limit", limit), - sql2.Named("offset", offset), - ).Scan(&stocks).Error + + b := builder.NewStockSQLBuilder(stockDate).Sources(source).Filter(filter).Limit(&limit).Offset(&offset) + sql, params := b.Build() + + err := s.db.Raw(sql, params).Scan(&stocks).Error if err != nil { return nil, err } return &stocks, nil } -func (s *Storage) GetStocks(stockDate time.Time) (*[]StockFull, error) { +func (s *Storage) GetStocks(stockDate time.Time, source *[]string, filter *string) (*[]StockFull, error) { var stocks []StockFull - err := s.db.Raw(sql_stocks_base, - sql2.Named("stock_date", stockDate), - ).Scan(&stocks).Error + b := builder.NewStockSQLBuilder(stockDate).Sources(source).Filter(filter) + sql, params := b.Build() + err := s.db.Raw(sql, params).Scan(&stocks).Error if err != nil { return nil, err } diff --git a/web/openapi/openapi.yml b/web/openapi/openapi.yml index cbdb3bf..67b4af1 100644 --- a/web/openapi/openapi.yml +++ b/web/openapi/openapi.yml @@ -40,6 +40,28 @@ components: $ref: '#/components/schemas/AuthInfo' schemas: + Marketplace: + type: object + properties: + code: + type: string + name: + type: string + shortName: + type: string + required: + - code + - name + - shortName + Dictionaries: + type: object + properties: + marketplaces: + type: array + items: + $ref: '#/components/schemas/Marketplace' + required: + - marketplaces PageProductParams: type: object required: @@ -538,6 +560,16 @@ paths: schema: type: string format: date + - in: query + name: source + schema: + type: array + items: + type: string + - in: query + name: filter + schema: + type: string description: Выгрузка отчета отстатоков за дату responses: 200: @@ -574,6 +606,16 @@ paths: required: true schema: type: integer + - in: query + name: source + schema: + type: array + items: + type: string + - in: query + name: filter + schema: + type: string description: Получение отстатоков за дату responses: "200": @@ -856,6 +898,21 @@ paths: $ref: '#/components/schemas/Profile' tags: - Auth + /dictionaries: + get: + description: Получение списка словарей + operationId: getDictionaries + security: + - ApiKeyAuth: [ ] + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Dictionaries' + tags: + - Dictionaries /dictionaries/positions: post: diff --git a/website/package-lock.json b/website/package-lock.json index 39b0471..18998df 100755 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -11,18 +11,20 @@ "@emotion/react": "latest", "@emotion/styled": "latest", "@mui/icons-material": "latest", - "@mui/joy": "5.0.0-beta.17", - "@mui/material": "^5.14.8", + "@mui/joy": "5.0.0-beta.24", + "@mui/material": "^5.15.6", "@mui/x-date-pickers": "^6.18.1", "@types/deep-equal": "^1.0.4", "@types/react": "latest", "@types/react-date-range": "^1.4.8", + "@types/react-datepicker": "^4.19.5", "@types/react-dom": "latest", "dayjs": "^1.11.9", "deep-equal": "^2.2.2", "moment": "^2.29.4", "react": "^17.0.0 || ^18.0.0", "react-date-range": "^1.4.0", + "react-datepicker": "^5.0.0", "react-dom": "^17.0.0 || ^18.0.0", "react-highlight-words": "^0.20.0", "react-router-dom": "^6.15.0", @@ -103,11 +105,11 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -199,12 +201,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -337,22 +339,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -504,17 +506,17 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -557,11 +559,11 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -570,9 +572,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz", - "integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -2134,9 +2136,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2159,20 +2161,20 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz", - "integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15", - "debug": "^4.1.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2180,12 +2182,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz", - "integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2723,28 +2725,42 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", - "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", "dependencies": { - "@floating-ui/utils": "^0.1.1" + "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz", - "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", "dependencies": { - "@floating-ui/core": "^1.4.1", - "@floating-ui/utils": "^0.1.1" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.8.tgz", + "integrity": "sha512-fOZb8BnJBrVohGPZ8RthDM5cHD9SnBKgY/U7LFXHhuwafSZD7TVmCX67+ezkkwxFbWpQGTEbgcjuHUDRonGy1g==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.8", + "@floating-ui/utils": "^0.2.1", + "tabbable": "^6.0.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", "dependencies": { - "@floating-ui/dom": "^1.5.1" + "@floating-ui/dom": "^1.6.1" }, "peerDependencies": { "react": ">=16.8.0", @@ -2752,9 +2768,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz", - "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==" + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", @@ -3647,26 +3663,24 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.14", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.14.tgz", - "integrity": "sha512-Je/9JzzYObsuLCIClgE8XvXNFb55IEz8n2NtStUfASfNiVrwiR8t6VVFFuhofehkyTIN34tq1qbBaOjCnOovBw==", - "dependencies": { - "@babel/runtime": "^7.22.10", - "@emotion/is-prop-valid": "^1.2.1", - "@floating-ui/react-dom": "^2.0.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.8", + "version": "5.0.0-beta.33", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.33.tgz", + "integrity": "sha512-WcSpoJUw/UYHXpvgtl4HyMar2Ar97illUpqiS/X1gtSBp6sdDW6kB2BJ9OlVQ+Kk/RL2GDp/WHA9sbjAYV35ow==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@floating-ui/react-dom": "^2.0.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "clsx": "^2.1.0", + "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -3679,15 +3693,10 @@ } } }, - "node_modules/@mui/base/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", - "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.6.tgz", + "integrity": "sha512-0aoWS4qvk1uzm9JBs83oQmIMIQeTBUeqqu8u+3uo2tMznrB5fIKqQVCbCgq+4Tm4jG+5F7dIvnjvQ2aV7UKtdw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" @@ -3719,17 +3728,17 @@ } }, "node_modules/@mui/joy": { - "version": "5.0.0-beta.17", - "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.17.tgz", - "integrity": "sha512-KQMfQe7P98jRYWcjTxLRnjAlWre0YGvZstpE+xNJyOn6aTnMomnAskMIG0s2+k5PcluyxTEZZKZZ0Usl3M5D6g==", - "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/base": "5.0.0-beta.26", - "@mui/core-downloads-tracker": "^5.14.20", - "@mui/system": "^5.14.20", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", - "clsx": "^2.0.0", + "version": "5.0.0-beta.24", + "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.24.tgz", + "integrity": "sha512-cKlIW56GsKKo9cVm+6pzNS+s4ch3r/SX/Zq5DA10I/TSuW9O5ptIOqeSs+WYpkyAzIoPkCpEXCPR/vGHpOt6MA==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/base": "5.0.0-beta.33", + "@mui/core-downloads-tracker": "^5.15.6", + "@mui/system": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { @@ -3758,50 +3767,19 @@ } } }, - "node_modules/@mui/joy/node_modules/@mui/base": { - "version": "5.0.0-beta.26", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", - "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", - "dependencies": { - "@babel/runtime": "^7.23.4", - "@floating-ui/react-dom": "^2.0.4", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", - "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/material": { - "version": "5.14.8", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.8.tgz", - "integrity": "sha512-fqvDGGF1pXwOOL/f0Gw+KHo/67hasRpf2ApTIJkbuONOk9AUb2jnYMEqCWmL2sUcbbE3ShMbHl8N7HPSsRv1/A==", - "dependencies": { - "@babel/runtime": "^7.22.10", - "@mui/base": "5.0.0-beta.14", - "@mui/core-downloads-tracker": "^5.14.8", - "@mui/system": "^5.14.8", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.8", - "@types/react-transition-group": "^4.4.6", - "clsx": "^2.0.0", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.6.tgz", + "integrity": "sha512-rw7bDdpi2kzfmcDN78lHp8swArJ5sBCKsn+4G3IpGfu44ycyWAWX0VdlvkjcR9Yrws2KIm7c+8niXpWHUDbWoA==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/base": "5.0.0-beta.33", + "@mui/core-downloads-tracker": "^5.15.6", + "@mui/system": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0", @@ -3812,7 +3790,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -3839,12 +3817,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/private-theming": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", - "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.6.tgz", + "integrity": "sha512-ZBX9E6VNUSscUOtU8uU462VvpvBS7eFl5VfxAzTRVQBHflzL+5KtnGrebgf6Nd6cdvxa1o0OomiaxSKoN2XDmg==", "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/utils": "^5.14.20", + "@babel/runtime": "^7.23.8", + "@mui/utils": "^5.15.6", "prop-types": "^15.8.1" }, "engines": { @@ -3865,11 +3843,11 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", - "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.6.tgz", + "integrity": "sha512-KAn8P8xP/WigFKMlEYUpU9z2o7jJnv0BG28Qu1dhNQVutsLVIFdRf5Nb+0ijp2qgtcmygQ0FtfRuXv5LYetZTg==", "dependencies": { - "@babel/runtime": "^7.23.4", + "@babel/runtime": "^7.23.8", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -3896,16 +3874,16 @@ } }, "node_modules/@mui/system": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", - "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", - "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/private-theming": "^5.14.20", - "@mui/styled-engine": "^5.14.19", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", - "clsx": "^2.0.0", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.6.tgz", + "integrity": "sha512-J01D//u8IfXvaEHMBQX5aO2l7Q+P15nt96c4NskX7yp5/+UuZP8XCQJhtBtLuj+M2LLyXHYGmCPeblsmmscP2Q==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "@mui/private-theming": "^5.15.6", + "@mui/styled-engine": "^5.15.6", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.6", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" }, @@ -3935,9 +3913,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.10", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", - "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -3948,11 +3926,11 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", - "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", + "version": "5.15.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.6.tgz", + "integrity": "sha512-qfEhf+zfU9aQdbzo1qrSWlbPQhH1nCgeYgwhOVnj9Bn39shJQitEnXpSQpSNag8+uty5Od6PxmlNKPTnPySRKA==", "dependencies": { - "@babel/runtime": "^7.23.4", + "@babel/runtime": "^7.23.8", "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -4044,37 +4022,6 @@ } } }, - "node_modules/@mui/x-date-pickers/node_modules/@mui/base": { - "version": "5.0.0-beta.24", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.24.tgz", - "integrity": "sha512-bKt2pUADHGQtqWDZ8nvL2Lvg2GNJyd/ZUgZAJoYzRgmnxBL9j36MSlS3+exEdYkikcnvVafcBtD904RypFKb0w==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@floating-ui/react-dom": "^2.0.4", - "@mui/types": "^7.2.9", - "@mui/utils": "^5.14.18", - "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -4875,6 +4822,17 @@ "date-fns": "^2.16.1" } }, + "node_modules/@types/react-datepicker": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.19.5.tgz", + "integrity": "sha512-tKpuj19p9T4sBQm3Bw13CPuhalo4CFOe/LcSUGJ5z6DmHoiBX3uq33iMKePeSEq7OxyU8O1rh5emAm92nyXZLg==", + "dependencies": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, "node_modules/@types/react-dom": { "version": "18.2.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", @@ -4884,9 +4842,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.9.tgz", - "integrity": "sha512-ZVNmWumUIh5NhH8aMD9CR2hdW0fNuYInlocZHaZ+dgk/1K49j1w/HoAuK1ki+pgscQrOFRTlXeoURtuzEkV3dg==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } @@ -6841,9 +6799,9 @@ } }, "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } @@ -9439,9 +9397,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true, "funding": [ { @@ -14440,9 +14398,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -15299,9 +15257,9 @@ } }, "node_modules/postcss": { - "version": "8.4.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", - "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "dev": true, "funding": [ { @@ -15318,7 +15276,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16923,6 +16881,22 @@ "react": "^0.14 || ^15.0.0-rc || >=15.0" } }, + "node_modules/react-datepicker": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-5.0.0.tgz", + "integrity": "sha512-AYpBCzinlE0fpltMtjjcpkiIyZVI3o9rbrhaMuf7oZcFp4LyRW2veCwORVFdcj4ProqnKTwNJBrTtauyanjMwg==", + "dependencies": { + "@floating-ui/react": "^0.26.2", + "classnames": "^2.2.6", + "date-fns": "^2.30.0", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.13.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -17055,6 +17029,11 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "dev": true }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "node_modules/react-highlight-words": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/react-highlight-words/-/react-highlight-words-0.20.0.tgz", @@ -17084,6 +17063,33 @@ "react": "0.14 || 15 - 18" } }, + "node_modules/react-onclickoutside": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", + "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x || ^18.x", + "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" + } + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -18809,6 +18815,11 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/tailwindcss": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", @@ -19595,6 +19606,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/website/package.json b/website/package.json index 07638e5..4b9dd79 100755 --- a/website/package.json +++ b/website/package.json @@ -3,18 +3,20 @@ "@emotion/react": "latest", "@emotion/styled": "latest", "@mui/icons-material": "latest", - "@mui/joy": "5.0.0-beta.17", - "@mui/material": "^5.14.8", + "@mui/joy": "5.0.0-beta.24", + "@mui/material": "^5.15.6", "@mui/x-date-pickers": "^6.18.1", "@types/deep-equal": "^1.0.4", "@types/react": "latest", "@types/react-date-range": "^1.4.8", + "@types/react-datepicker": "^4.19.5", "@types/react-dom": "latest", "dayjs": "^1.11.9", "deep-equal": "^2.2.2", "moment": "^2.29.4", "react": "^17.0.0 || ^18.0.0", "react-date-range": "^1.4.0", + "react-datepicker": "^5.0.0", "react-dom": "^17.0.0 || ^18.0.0", "react-highlight-words": "^0.20.0", "react-router-dom": "^6.15.0", diff --git a/website/src/client/index.ts b/website/src/client/index.ts index 2402f6d..c579144 100755 --- a/website/src/client/index.ts +++ b/website/src/client/index.ts @@ -8,10 +8,12 @@ export { OpenAPI } from './core/OpenAPI'; export type { OpenAPIConfig } from './core/OpenAPI'; export type { AuthInfo } from './models/AuthInfo'; +export type { Dictionaries } from './models/Dictionaries'; export type { DictPosition } from './models/DictPosition'; export type { DictPositions } from './models/DictPositions'; export type { ErrorData } from './models/ErrorData'; export type { LoginInfo } from './models/LoginInfo'; +export type { Marketplace } from './models/Marketplace'; export type { Order } from './models/Order'; export type { OrderProduct } from './models/OrderProduct'; export type { OrderProducts } from './models/OrderProducts'; diff --git a/website/src/client/models/Dictionaries.ts b/website/src/client/models/Dictionaries.ts new file mode 100644 index 0000000..ecbb9f2 --- /dev/null +++ b/website/src/client/models/Dictionaries.ts @@ -0,0 +1,11 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { Marketplace } from './Marketplace'; + +export type Dictionaries = { + marketplaces: Array; +}; + diff --git a/website/src/client/models/Marketplace.ts b/website/src/client/models/Marketplace.ts new file mode 100644 index 0000000..4d397ce --- /dev/null +++ b/website/src/client/models/Marketplace.ts @@ -0,0 +1,11 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type Marketplace = { + code: string; + name: string; + shortName: string; +}; + diff --git a/website/src/client/services/DictionariesService.ts b/website/src/client/services/DictionariesService.ts index 9d8ccb6..536b1bf 100644 --- a/website/src/client/services/DictionariesService.ts +++ b/website/src/client/services/DictionariesService.ts @@ -2,6 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { Dictionaries } from '../models/Dictionaries'; import type { DictPositions } from '../models/DictPositions'; import type { PageProductParams } from '../models/PageProductParams'; import type { Warehouse } from '../models/Warehouse'; @@ -13,6 +14,18 @@ import { request as __request } from '../core/request'; export class DictionariesService { + /** + * Получение списка словарей + * @returns Dictionaries OK + * @throws ApiError + */ + public static getDictionaries(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/dictionaries', + }); + } + /** * Получение списка позиций * @param requestBody diff --git a/website/src/client/services/StocksService.ts b/website/src/client/services/StocksService.ts index 66e6ba9..44b23c4 100644 --- a/website/src/client/services/StocksService.ts +++ b/website/src/client/services/StocksService.ts @@ -36,17 +36,23 @@ export class StocksService { * Получение остатков товаров * Выгрузка отчета отстатоков за дату * @param date Дата (YYYY-MM-DD) + * @param source + * @param filter * @returns binary OK * @throws ApiError */ public static exportStocks( date: string, + source?: Array, + filter?: string, ): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/stocks/export', query: { 'date': date, + 'source': source, + 'filter': filter, }, }); } @@ -57,6 +63,8 @@ export class StocksService { * @param date Дата (YYYY-MM-DD) * @param limit * @param offset + * @param source + * @param filter * @returns StocksFull OK * @throws ApiError */ @@ -64,6 +72,8 @@ export class StocksService { date: string, limit: number, offset: number, + source?: Array, + filter?: string, ): CancelablePromise { return __request(OpenAPI, { method: 'GET', @@ -72,6 +82,8 @@ export class StocksService { 'date': date, 'limit': limit, 'offset': offset, + 'source': source, + 'filter': filter, }, errors: { 404: `Not Found`, diff --git a/website/src/components/JoyDatePicker.tsx b/website/src/components/JoyDatePicker.tsx index 14afd6a..6bfe10c 100755 --- a/website/src/components/JoyDatePicker.tsx +++ b/website/src/components/JoyDatePicker.tsx @@ -118,7 +118,12 @@ const JoyDatePicker = React.forwardRef( ; + endAdornment?: React.ReactNode; + startAdornment?: React.ReactNode; + }; + formControlSx?: InputProps['sx']; +} + +type JoyFieldComponent = (( + props: JoyFieldProps & React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +const JoyField = React.forwardRef( + (props: JoyFieldProps, ref: React.Ref) => { + const { + disabled, + id, + label, + InputProps: { ref: containerRef, startAdornment, endAdornment } = {}, + formControlSx, + endDecorator, + startDecorator, + slotProps, + ...other + } = props; + + return ( + + {label} + + {startAdornment} + {startDecorator} + + } + endDecorator={ + + {endAdornment} + {endDecorator} + + } + slotProps={{ + ...slotProps, + root: { ...slotProps?.root, ref: containerRef }, + }} + {...other} + /> + + ); + }, +) as JoyFieldComponent; + +interface JoyDateFieldProps + extends UseDateFieldProps, + BaseSingleInputFieldProps< + Dayjs | null, + Dayjs, + FieldSection, + DateValidationError + > {} + +const JoyDateField = React.forwardRef( + (props: JoyDateFieldProps, ref: React.Ref) => { + const { + inputRef: externalInputRef, + slots, + slotProps, + ...textFieldProps + } = props; + + const { + onClear, + clearable, + ref: inputRef, + ...fieldProps + } = useDateField({ + props: textFieldProps, + inputRef: externalInputRef, + }); + + /* If you don't need a clear button, you can skip the use of this hook */ + const { InputProps: ProcessedInputProps, fieldProps: processedFieldProps } = + useClearableField< + {}, + typeof textFieldProps.InputProps, + DateFieldSlotsComponent, + DateFieldSlotsComponentsProps + >({ + onClear, + clearable, + fieldProps, + InputProps: fieldProps.InputProps, + slots, + slotProps, + }); + + return ( + + ); + }, +); + +const JoyDatePicker = React.forwardRef( + (props: DatePickerProps, ref: React.Ref) => { + return ( + + ); + }, +); + +/** + * This component is for syncing the theme mode of this demo with the MUI docs mode. + * You might not need this component in your project. + */ +function SyncThemeMode({ mode }: { mode: 'light' | 'dark' }) { + const { setMode } = useColorScheme(); + const { setMode: setMaterialMode } = useMaterialColorScheme(); + React.useEffect(() => { + setMode(mode); + setMaterialMode(mode); + }, [mode, setMode, setMaterialMode]); + return null; +} + +export default function PickerWithJoyField(props: DatePickerProps) { + const materialTheme = useMaterialTheme(); + return ( + + + + + + + + + ); +} \ No newline at end of file diff --git a/website/src/context/actions/index.ts b/website/src/context/actions/index.ts index 53d4473..0c89403 100755 --- a/website/src/context/actions/index.ts +++ b/website/src/context/actions/index.ts @@ -1,5 +1,5 @@ import { IAction, IActionFunction } from '../index'; -import { AuthService, OpenAPI, Profile } from 'client'; +import { AuthService, Dictionaries, DictionariesService, OpenAPI, Profile } from 'client'; import { Dispatch } from 'react'; const SetError = (error?: string): IAction => { @@ -82,6 +82,13 @@ const SetProfile = (profile: Profile): IAction => { } } +const SetDicts = (dicts: Dictionaries): IAction => { + return { + type: "SET_DICT", + payload: dicts + } +} + const CleanProfile = (): IAction => { return { type: "SET_PROFILE", @@ -91,17 +98,24 @@ const CleanProfile = (): IAction => { const LoadProfile = (): IActionFunction => { return (dispatch: Dispatch) => { - AuthService.profile() - .then(resp => { - dispatch(SetProfile(resp)) - }).catch(err => { - const description = err.body.description - dispatch(SetLogout(description)); + + const reqProfile = AuthService.profile() + const reqDicts = DictionariesService.getDictionaries() + + Promise.all([reqProfile, reqDicts]).then(([ + respProfile, + respDicts + ]) => { + dispatch(SetDicts(respDicts)) + dispatch(SetProfile(respProfile)) + }).catch(err => { + const description = err.body.description + dispatch(SetLogout(description)); }) } } -const SetMenuActive = (key: string): IAction => { +const SetMenuActive = (key: string): IAction => { return { type: "SET_SIDEBAR_ACTIVE", payload: key @@ -119,5 +133,6 @@ export { SetError, SetAuthLoading, LoadProfile, - SetMenuActive + SetMenuActive, + SetDicts } \ No newline at end of file diff --git a/website/src/context/index.tsx b/website/src/context/index.tsx index 9666e9a..25d1a64 100755 --- a/website/src/context/index.tsx +++ b/website/src/context/index.tsx @@ -1,13 +1,5 @@ import * as React from 'react'; -import { - createContext, - Dispatch, - ReactNode, - ReducerStateWithoutAction, - ReducerWithoutAction, - useContext, - useReducer -} from 'react'; +import { createContext, Dispatch, ReactNode, useContext, useReducer } from 'react'; import HomeRoundedIcon from '@mui/icons-material/HomeRounded'; import DashboardRoundedIcon from '@mui/icons-material/DashboardRounded'; import DynamicFeedRoundedIcon from '@mui/icons-material/DynamicFeedRounded'; @@ -17,7 +9,7 @@ import QrCode2RoundedIcon from '@mui/icons-material/QrCode2Rounded'; import BlockRoundedIcon from '@mui/icons-material/BlockRounded'; import DeviceHubRoundedIcon from '@mui/icons-material/DeviceHubRounded'; import { Cluster } from '../layouts/dictionary/cluster'; -import { Profile } from 'client'; +import { Dictionaries, Profile } from 'client'; interface ISubMenuData { name: string, @@ -26,6 +18,7 @@ interface ISubMenuData { icon?: React.JSX.Element, component?: React.JSX.Element } + interface IMenuData { name: string, href?: string, @@ -46,6 +39,7 @@ interface IContent { activeSubIndex: number, data: IMenuData[] }, + dicts: IDicts, error?: string } @@ -67,6 +61,16 @@ export interface IAuth { error?: string } +export interface IMarketplaceDictItem { + code: string + name: string + shortName: string +} + +export interface IDicts { + marketplaces: IMarketplaceDictItem[] +} + const InitState: IContent = { sidebar: { active: "menu-home-id", @@ -75,6 +79,9 @@ const InitState: IContent = { isAuth: sessionStorage.getItem("access_token") ? true : false, isLoading: false }, + dicts: { + marketplaces: [] + }, menu: { activeIndex: 0, activeSubIndex: 0, @@ -107,18 +114,18 @@ const InitState: IContent = { { name: "Справочники", type: "header" - },{ + }, { name: "Кластеры", type: "menu", index: 0, icon: , component: - },{ + }, { name: "Выведенные позиции", type: "menu", index: 1, icon: - },{ + }, { name: "Штрих-коды", type: "menu", index: 2, @@ -140,6 +147,13 @@ YContext.displayName = "YContext" function reducer(state: IContent, action: IAction): IContent { switch (action.type) { + case "SET_DICT": { + console.log(action.payload) + return { + ...state, + dicts: action.payload + } + } case "SET_SIDEBAR_ACTIVE": { return { ...state, @@ -151,7 +165,7 @@ function reducer(state: IContent, action: IAction): IContent { } case "SET_AUTH_LOADING": { return { - ...state, auth: { ...state.auth, isLoading: action.payload } + ...state, auth: {...state.auth, isLoading: action.payload} } } case "SET_ERROR": { @@ -161,7 +175,7 @@ function reducer(state: IContent, action: IAction): IContent { } case "SET_AUTH": { return { - ...state, auth: { ...state.auth, ...action.payload } + ...state, auth: {...state.auth, ...action.payload} } } case "FIRST_MENU_SET_ACTIVE": { diff --git a/website/src/layouts/auth/index.tsx b/website/src/layouts/auth/index.tsx index 563b190..f2faff6 100755 --- a/website/src/layouts/auth/index.tsx +++ b/website/src/layouts/auth/index.tsx @@ -1,6 +1,5 @@ import React, { useEffect } from 'react'; import LoginPage from 'layouts/loginPage'; -import useAuth from 'hooks/useAuth'; import { LoadProfile } from 'context/actions'; import ProfileLoader from 'layouts/profileLoader'; import { useController } from 'context'; @@ -12,7 +11,7 @@ interface IAuthProviderProps { function AuthProvider(props: IAuthProviderProps): React.JSX.Element { const {state, dispatch} = useController(); const {isAuth} = state.auth; - const {profile} = state; + const {profile, dicts} = state; useEffect(() => { if (isAuth) { diff --git a/website/src/layouts/stock/index.tsx b/website/src/layouts/stock/index.tsx index 05e8de4..4e1c1e8 100644 --- a/website/src/layouts/stock/index.tsx +++ b/website/src/layouts/stock/index.tsx @@ -2,23 +2,27 @@ import Box from "@mui/joy/Box"; import Typography from "@mui/joy/Typography"; import Button from "@mui/joy/Button"; import DownloadRoundedIcon from "@mui/icons-material/DownloadRounded"; -import JoyDataGrid, {IColumn} from "../../components/JoyDataGrid"; +import JoyDataGrid, { IColumn } from "../../components/JoyDataGrid"; import * as React from "react"; -import {Fragment, useEffect, useState} from "react"; -import {SetError, SetMenuActive} from "../../context/actions"; -import {useController} from "../../context"; -import {LocalizationProvider} from "@mui/x-date-pickers"; -import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"; -import JoyDatePicker from "../../components/JoyDatePicker"; +import { Fragment, useEffect, useState } from "react"; +import { SetError, SetMenuActive } from "../../context/actions"; +import { useController } from "../../context"; import dayjs from "dayjs"; -import { OrdersService, ProductParams, type StockFull, StocksService } from "../../client"; +import { type StockFull, StocksService } from "../../client"; +import Select from '@mui/joy/Select'; +import Option from '@mui/joy/Option'; +import Input from '@mui/joy/Input'; +import SearchIcon from '@mui/icons-material/Search'; +import { KeyboardArrowDown } from '@mui/icons-material'; +import { Chip } from '@mui/joy'; +import PickerWithJoyField from 'components/PickerWithJoyField'; const columns: IColumn[] = [ { field: 'stockDate', headerName: 'Дата', width: '100px', - type:'date' + type: 'date' }, { field: 'source', headerName: 'МП', @@ -75,13 +79,19 @@ const columns: IColumn[] = [ ] export default function Stocks() { - const {dispatch} = useController() + const {dispatch, state} = useController() + + const {marketplaces} = state.dicts + const defaultMarketplaces = marketplaces.map(mp => mp.code) + const [page, setPage] = useState(0) const [pageSize, setPageSize] = useState(25) const [total, setTotal] = useState(0) const [rows, setRows] = useState([]) const [isLoading, setIsLoading] = useState(false) const [isDownload, setIsDownload] = useState(false) + const [sources, setSources] = useState(defaultMarketplaces) + const [filter, setFilter] = useState(undefined) const [date, setDate] = useState(dayjs().subtract(1, 'day')) @@ -91,7 +101,7 @@ export default function Stocks() { function handleDownloadFile() { setIsDownload(true) - StocksService.exportStocks(date.format("YYYY-MM-DD")) + StocksService.exportStocks(date.format("YYYY-MM-DD"), sources, filter) .then((blob: Blob) => { //const blob: Blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); const fileURL = URL.createObjectURL(blob); @@ -108,11 +118,13 @@ export default function Stocks() { StocksService.getStocksWithPages( date.format('YYYY-MM-DD'), pageSize, - page * pageSize + page * pageSize, + sources, + filter ).then(req => { - setTotal(req.count) - setRows(req.items) - }) + setTotal(req.count) + setRows(req.items) + }) .catch(err => { dispatch(SetError(err.body.description)) }) @@ -121,7 +133,78 @@ export default function Stocks() { useEffect(() => { refreshRows() - }, [date, page, pageSize]); + }, [date, page, pageSize, sources, filter]); + + const handleSourceChange = ( + event: React.SyntheticEvent | null, + newValue: string[] | null, + ) => { + setSources(newValue ?? sources) + setPage(0) + }; + + const handleOnKeyDown = (event: any) => { + if (event.key === 'Enter') { + setFilter(event.target.value) + setPage(0) + event.preventDefault(); + } + } + + function renderFilters() { + return + + + } + // onChange={handleChangeFilterText} + onKeyDown={handleOnKeyDown} + /> + + + } return ( @@ -148,20 +231,15 @@ export default function Stocks() { justifyContent: 'space-between', }} > - - setDate(event ?? date)} - /> - + { + setDate(event ?? date) + setPage(0) + }} + />