product-procedures #52
2
.env
2
.env
@@ -58,3 +58,5 @@ FILE_MAAL_PL_PASSWORD=1FnwqcEgIUjQHjt1
|
|||||||
|
|
||||||
IMAGE_PREFIX=https://www.naluconcept.com # remove prefix to serv them from same host as presta
|
IMAGE_PREFIX=https://www.naluconcept.com # remove prefix to serv them from same host as presta
|
||||||
CORS_ORGIN=https://www.naluconcept.com
|
CORS_ORGIN=https://www.naluconcept.com
|
||||||
|
|
||||||
|
DSN=root:Maal12345678@tcp(localhost:3306)/nalu
|
||||||
@@ -2,13 +2,17 @@ package public
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
|
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
|
||||||
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/response"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
@@ -345,9 +349,58 @@ func (h *AuthHandler) CompleteRegistration(c fiber.Ctx) error {
|
|||||||
return c.Status(fiber.StatusCreated).JSON(response)
|
return c.Status(fiber.StatusCreated).JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates JWT Tokens
|
// Updates JWT Tokens. Requires authentication and updates access token only
|
||||||
func (h *AuthHandler) UpdateJWTToken(c fiber.Ctx) error {
|
func (h *AuthHandler) UpdateJWTToken(c fiber.Ctx) error {
|
||||||
return h.authService.UpdateJWTToken(c)
|
userLocals, ok := c.Locals(constdata.USER_LOCALES_NAME).(*model.UserSession)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrNotAuthenticated)))
|
||||||
|
}
|
||||||
|
|
||||||
|
user := model.Customer{
|
||||||
|
ID: userLocals.UserID,
|
||||||
|
Email: userLocals.Email,
|
||||||
|
Role: userLocals.Role,
|
||||||
|
LangID: userLocals.LangID,
|
||||||
|
CountryID: userLocals.CountryID,
|
||||||
|
IsActive: userLocals.IsActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse language and country_id from query params
|
||||||
|
langIDStr := c.Query("lang_id")
|
||||||
|
|
||||||
|
if langIDStr != "" {
|
||||||
|
parsedID, err := strconv.ParseUint(langIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadLangID)))
|
||||||
|
}
|
||||||
|
user.LangID = uint(parsedID)
|
||||||
|
}
|
||||||
|
|
||||||
|
countryIDStr := c.Query("country_id")
|
||||||
|
|
||||||
|
if countryIDStr != "" {
|
||||||
|
parsedID, err := strconv.ParseUint(countryIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadCountryID)))
|
||||||
|
}
|
||||||
|
user.CountryID = uint(parsedID)
|
||||||
|
}
|
||||||
|
|
||||||
|
newAccessToken, err := h.authService.UpdateJWTToken(&user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{
|
||||||
|
"error": responseErrors.GetErrorCode(c, err),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// does not reset refresh token
|
||||||
|
h.setAuthCookies(c, newAccessToken, "")
|
||||||
|
|
||||||
|
return c.JSON(response.Make(&fiber.Map{"token": newAccessToken}, 0, i18n.T_(c, response.Message_OK)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoogleLogin redirects the user to Google's OAuth2 consent page
|
// GoogleLogin redirects the user to Google's OAuth2 consent page
|
||||||
@@ -414,12 +467,12 @@ func (h *AuthHandler) GoogleCallback(c fiber.Ctx) error {
|
|||||||
|
|
||||||
// Redirect to the locale-prefixed charts page after successful Google login.
|
// Redirect to the locale-prefixed charts page after successful Google login.
|
||||||
// The user's preferred language is stored in the auth response; fall back to "en".
|
// The user's preferred language is stored in the auth response; fall back to "en".
|
||||||
lang, err := h.authService.GetLangISOCode(response.User.LangID)
|
lang_iso_code, err := h.authService.GetLangISOCode(response.User.LangID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadLangID)).JSON(fiber.Map{
|
return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{
|
||||||
"error": responseErrors.GetErrorCode(c, responseErrors.ErrBadLangID),
|
"error": responseErrors.GetErrorCode(c, err),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect().To(h.config.App.BaseURL + "/" + lang)
|
return c.Redirect().To(h.config.App.BaseURL + "/" + lang_iso_code)
|
||||||
}
|
}
|
||||||
|
|||||||
98
app/delivery/web/api/restricted/list.go
Normal file
98
app/delivery/web/api/restricted/list.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package restricted
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/service/listService"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/query_params"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/response"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListHandler handles endpoints that list various things (e.g. products or users)
|
||||||
|
type ListHandler struct {
|
||||||
|
listService *listService.ListService
|
||||||
|
config *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewListHandler creates a new ListHandler instance
|
||||||
|
func NewListHandler() *ListHandler {
|
||||||
|
listService := listService.New()
|
||||||
|
return &ListHandler{
|
||||||
|
listService: listService,
|
||||||
|
config: config.Get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListHandlerRoutes(r fiber.Router) fiber.Router {
|
||||||
|
handler := NewListHandler()
|
||||||
|
|
||||||
|
r.Get("/list-products", handler.ListProducts)
|
||||||
|
r.Get("/list-users", handler.ListUsers)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ListHandler) ListProducts(c fiber.Ctx) error {
|
||||||
|
paging, filters, err := query_params.ParseFilters[model.Product](c, columnMappingListProducts)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
id_lang, ok := c.Locals("langID").(uint)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
listing, err := h.listService.ListProducts(id_lang, paging, filters)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(&listing.Items, int(listing.Count), i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnMappingListProducts map[string]string = map[string]string{
|
||||||
|
"product_id": "ps.id_product",
|
||||||
|
"name": "pl.name",
|
||||||
|
"reference": "p.reference",
|
||||||
|
"category_name": "cl.name",
|
||||||
|
"category_id": "cp.id_category",
|
||||||
|
"quantity": "sa.quantity",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ListHandler) ListUsers(c fiber.Ctx) error {
|
||||||
|
paging, filters, err := query_params.ParseFilters[model.Customer](c, columnMappingListUsers)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
id_lang, ok := c.Locals("langID").(uint)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
listing, err := h.listService.ListUsers(id_lang, paging, filters)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(&listing.Items, int(listing.Count), i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnMappingListUsers map[string]string = map[string]string{
|
||||||
|
"user_id": "users.id",
|
||||||
|
"email": "users.email",
|
||||||
|
"first_name": "users.first_name",
|
||||||
|
"second_name": "users.second_name",
|
||||||
|
"role": "users.role",
|
||||||
|
}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package restricted
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/listProductsService"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/query/query_params"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/response"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
|
||||||
"github.com/gofiber/fiber/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListProductsHandler handles endpoints that receive, save and translate product descriptions.
|
|
||||||
type ListProductsHandler struct {
|
|
||||||
listProductsService *listProductsService.ListProductsService
|
|
||||||
config *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewListProductsHandler creates a new ListProductsHandler instance
|
|
||||||
func NewListProductsHandler() *ListProductsHandler {
|
|
||||||
listProductsService := listProductsService.New()
|
|
||||||
return &ListProductsHandler{
|
|
||||||
listProductsService: listProductsService,
|
|
||||||
config: config.Get(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListProductsHandlerRoutes(r fiber.Router) fiber.Router {
|
|
||||||
handler := NewListProductsHandler()
|
|
||||||
|
|
||||||
r.Get("/get-listing", handler.GetListing)
|
|
||||||
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ListProductsHandler) GetListing(c fiber.Ctx) error {
|
|
||||||
paging, filters, err := query_params.ParseFilters[model.Product](c, columnMappingGetListing)
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(responseErrors.GetErrorStatus(err)).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
id_lang, ok := c.Locals("langID").(uint)
|
|
||||||
if !ok {
|
|
||||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
|
||||||
}
|
|
||||||
|
|
||||||
listing, err := h.listProductsService.GetListing(id_lang, paging, filters)
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(responseErrors.GetErrorStatus(err)).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(response.Make(&listing.Items, int(listing.Count), i18n.T_(c, response.Message_OK)))
|
|
||||||
}
|
|
||||||
|
|
||||||
var columnMappingGetListing map[string]string = map[string]string{
|
|
||||||
"product_id": "ps.id_product",
|
|
||||||
"name": "pl.name",
|
|
||||||
"reference": "p.reference",
|
|
||||||
"category_name": "cl.name",
|
|
||||||
"category_id": "cp.id_category",
|
|
||||||
"quantity": "sa.quantity",
|
|
||||||
}
|
|
||||||
@@ -94,9 +94,9 @@ func (s *Server) Setup() error {
|
|||||||
productTranslation := s.restricted.Group("/product-translation")
|
productTranslation := s.restricted.Group("/product-translation")
|
||||||
restricted.ProductTranslationHandlerRoutes(productTranslation)
|
restricted.ProductTranslationHandlerRoutes(productTranslation)
|
||||||
|
|
||||||
// listing products routes (restricted)
|
// lists of things routes (restricted)
|
||||||
listProducts := s.restricted.Group("/list-products")
|
list := s.restricted.Group("/list")
|
||||||
restricted.ListProductsHandlerRoutes(listProducts)
|
restricted.ListHandlerRoutes(list)
|
||||||
|
|
||||||
restricted.ProductsHandlerRoutes(s.restricted)
|
restricted.ProductsHandlerRoutes(s.restricted)
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,17 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
||||||
|
|
||||||
// Represents a country together with its associated currency
|
// Represents a country together with its associated currency
|
||||||
type Country struct {
|
type Country struct {
|
||||||
ID uint `gorm:"primaryKey;column:id" json:"id"`
|
ID uint `gorm:"primaryKey;column:id" json:"id"`
|
||||||
Name string `gorm:"column:name" json:"name"`
|
Name string `gorm:"column:name" json:"name"`
|
||||||
Flag string `gorm:"size:16;not null;column:flag" json:"flag"`
|
Flag string `gorm:"size:16;not null;column:flag" json:"flag"`
|
||||||
CurrencyID uint `gorm:"column:id_currency" json:"currency_id"`
|
|
||||||
CurrencyISOCode string `gorm:"column:iso_code" json:"currency_iso_code"`
|
PSCurrencyID uint `gorm:"column:currency_id" json:"currency_id"`
|
||||||
CurrencyName string `gorm:"column:name" json:"currency_name"`
|
PSCurrency *dbmodel.PsCurrency `gorm:"foreignKey:PSCurrencyID;references:IDCurrency" json:"ps_currency"`
|
||||||
// PSCountryID int `gorm:"column:id_country" json:"ps_country_id"`
|
|
||||||
// PSCountry *PSCountry `gorm:"foreignKey:PSCountryID;references:ID" json:"ps_country"`
|
|
||||||
PSCurrencyID uint `gorm:"column:currency" json:"currency"`
|
|
||||||
PSCurrency *PSCurrency `gorm:"foreignKey:PSCurrencyID;references:currency_id" json:"ps_currency"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Country) TableName() string {
|
func (Country) TableName() string {
|
||||||
return "b2b_countries"
|
return "b2b_countries"
|
||||||
}
|
}
|
||||||
|
|
||||||
type PSCountry struct {
|
|
||||||
CurrencyID uint `gorm:"column:id_currency" json:"currency_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (PSCountry) TableName() string {
|
|
||||||
return "ps_country"
|
|
||||||
}
|
|
||||||
|
|
||||||
type PSCurrency struct {
|
|
||||||
Currency int `gorm:"column:currency" json:"currency"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -144,3 +144,11 @@ type RefreshToken struct {
|
|||||||
func (RefreshToken) TableName() string {
|
func (RefreshToken) TableName() string {
|
||||||
return "b2b_refresh_tokens"
|
return "b2b_refresh_tokens"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserInList struct {
|
||||||
|
UserID uint `gorm:"primaryKey;column:id" json:"user_id"`
|
||||||
|
Email string `gorm:"column:email" json:"email"`
|
||||||
|
FirstName string `gorm:"column:first_name" json:"first_name"`
|
||||||
|
LastName string `gorm:"column:last_name" json:"last_name"`
|
||||||
|
Role string `gorm:"column:role" json:"role"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ func (*PsGroupReduction) TableName() string {
|
|||||||
|
|
||||||
var PsGroupReductionCols = struct {
|
var PsGroupReductionCols = struct {
|
||||||
IDGroupReduction gormcol.Field
|
IDGroupReduction gormcol.Field
|
||||||
IDGroup gormcol.Field
|
IDGroup gormcol.Field
|
||||||
IDCategory gormcol.Field
|
IDCategory gormcol.Field
|
||||||
Reduction gormcol.Field
|
Reduction gormcol.Field
|
||||||
}{
|
}{
|
||||||
IDGroupReduction: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_group_reduction"),
|
IDGroupReduction: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_group_reduction"),
|
||||||
IDGroup: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_group"),
|
IDGroup: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_group"),
|
||||||
IDCategory: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_category"),
|
IDCategory: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "id_category"),
|
||||||
Reduction: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "reduction"),
|
Reduction: gormcol.Field{}.Set((&PsGroupReduction{}).TableName(), "reduction"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ func (*PsProductAttributeCombination) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var PsProductAttributeCombinationCols = struct {
|
var PsProductAttributeCombinationCols = struct {
|
||||||
IDAttribute gormcol.Field
|
IDAttribute gormcol.Field
|
||||||
IDProductAttribute gormcol.Field
|
IDProductAttribute gormcol.Field
|
||||||
}{
|
}{
|
||||||
IDAttribute: gormcol.Field{}.Set((&PsProductAttributeCombination{}).TableName(), "id_attribute"),
|
IDAttribute: gormcol.Field{}.Set((&PsProductAttributeCombination{}).TableName(), "id_attribute"),
|
||||||
IDProductAttribute: gormcol.Field{}.Set((&PsProductAttributeCombination{}).TableName(), "id_product_attribute"),
|
IDProductAttribute: gormcol.Field{}.Set((&PsProductAttributeCombination{}).TableName(), "id_product_attribute"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ func (*PsProductGroupReductionCache) TableName() string {
|
|||||||
|
|
||||||
var PsProductGroupReductionCacheCols = struct {
|
var PsProductGroupReductionCacheCols = struct {
|
||||||
IDProduct gormcol.Field
|
IDProduct gormcol.Field
|
||||||
IDGroup gormcol.Field
|
IDGroup gormcol.Field
|
||||||
Reduction gormcol.Field
|
Reduction gormcol.Field
|
||||||
}{
|
}{
|
||||||
IDProduct: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "id_product"),
|
IDProduct: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "id_product"),
|
||||||
IDGroup: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "id_group"),
|
IDGroup: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "id_group"),
|
||||||
Reduction: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "reduction"),
|
Reduction: gormcol.Field{}.Set((&PsProductGroupReductionCache{}).TableName(), "reduction"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ func (*PsPshowPshowproducttabsHook) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var PsPshowPshowproducttabsHookCols = struct {
|
var PsPshowPshowproducttabsHookCols = struct {
|
||||||
IDHook gormcol.Field
|
IDHook gormcol.Field
|
||||||
HookName gormcol.Field
|
HookName gormcol.Field
|
||||||
PrestaIDHook gormcol.Field
|
PrestaIDHook gormcol.Field
|
||||||
}{
|
}{
|
||||||
IDHook: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "id_hook"),
|
IDHook: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "id_hook"),
|
||||||
HookName: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "hook_name"),
|
HookName: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "hook_name"),
|
||||||
PrestaIDHook: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "presta_id_hook"),
|
PrestaIDHook: gormcol.Field{}.Set((&PsPshowPshowproducttabsHook{}).TableName(), "presta_id_hook"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package listProductsRepo
|
package listRepo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||||
@@ -7,25 +7,27 @@ import (
|
|||||||
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
||||||
|
"git.ma-al.com/goc_marek/gormcol"
|
||||||
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
|
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UIListProductsRepo interface {
|
type UIListRepo interface {
|
||||||
GetListing(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error)
|
ListProducts(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error)
|
||||||
|
ListUsers(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.UserInList], error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListProductsRepo struct{}
|
type ListRepo struct{}
|
||||||
|
|
||||||
func New() UIListProductsRepo {
|
func New() UIListRepo {
|
||||||
return &ListProductsRepo{}
|
return &ListRepo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ListProductsRepo) GetListing(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error) {
|
func (repo *ListRepo) ListProducts(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error) {
|
||||||
var listing []model.ProductInList
|
var list []model.ProductInList
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
query := db.Get().
|
query := db.Get().
|
||||||
Table("ps_product_shop ps").
|
Table(gormcol.Field.Tab(dbmodel.PsProductShopCols.Active)+" AS ps").
|
||||||
Select(`
|
Select(`
|
||||||
ps.id_product AS product_id,
|
ps.id_product AS product_id,
|
||||||
pl.name AS name,
|
pl.name AS name,
|
||||||
@@ -67,13 +69,53 @@ func (repo *ListProductsRepo) GetListing(id_lang uint, p find.Paging, filt *filt
|
|||||||
Order("ps.id_product DESC").
|
Order("ps.id_product DESC").
|
||||||
Limit(p.Limit()).
|
Limit(p.Limit()).
|
||||||
Offset(p.Offset()).
|
Offset(p.Offset()).
|
||||||
Find(&listing).Error
|
Find(&list).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return find.Found[model.ProductInList]{}, err
|
return find.Found[model.ProductInList]{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return find.Found[model.ProductInList]{
|
return find.Found[model.ProductInList]{
|
||||||
Items: listing,
|
Items: list,
|
||||||
|
Count: uint(total),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ListRepo) ListUsers(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.UserInList], error) {
|
||||||
|
var list []model.UserInList
|
||||||
|
var total int64
|
||||||
|
|
||||||
|
query := db.Get().
|
||||||
|
Table("b2b_customers AS users").
|
||||||
|
Select(`
|
||||||
|
users.id AS id,
|
||||||
|
users.email AS email,
|
||||||
|
users.first_name AS first_name,
|
||||||
|
users.last_name AS last_name,
|
||||||
|
users.role AS role
|
||||||
|
`)
|
||||||
|
|
||||||
|
// Apply all filters
|
||||||
|
if filt != nil {
|
||||||
|
filt.ApplyAll(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run counter first as query is without limit and offset
|
||||||
|
err := query.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return find.Found[model.UserInList]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.
|
||||||
|
Order("users.id DESC").
|
||||||
|
Limit(p.Limit()).
|
||||||
|
Offset(p.Offset()).
|
||||||
|
Find(&list).Error
|
||||||
|
if err != nil {
|
||||||
|
return find.Found[model.UserInList]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return find.Found[model.UserInList]{
|
||||||
|
Items: list,
|
||||||
Count: uint(total),
|
Count: uint(total),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||||
@@ -14,13 +13,9 @@ import (
|
|||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/emailService"
|
"git.ma-al.com/goc_daniel/b2b/app/service/emailService"
|
||||||
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/response"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||||
|
|
||||||
"github.com/dlclark/regexp2"
|
"github.com/dlclark/regexp2"
|
||||||
"github.com/gofiber/fiber/v3"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -167,7 +162,7 @@ func (s *AuthService) Register(req *model.RegisterRequest) error {
|
|||||||
baseURL := config.Get().App.BaseURL
|
baseURL := config.Get().App.BaseURL
|
||||||
lang, err := s.GetLangISOCode(req.LangID)
|
lang, err := s.GetLangISOCode(req.LangID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return responseErrors.ErrBadLangID
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.email.SendVerificationEmail(user.Email, user.EmailVerificationToken, baseURL, lang); err != nil {
|
if err := s.email.SendVerificationEmail(user.Email, user.EmailVerificationToken, baseURL, lang); err != nil {
|
||||||
@@ -276,7 +271,7 @@ func (s *AuthService) RequestPasswordReset(emailAddr string) error {
|
|||||||
baseURL := config.Get().App.BaseURL
|
baseURL := config.Get().App.BaseURL
|
||||||
lang, err := s.GetLangISOCode(user.LangID)
|
lang, err := s.GetLangISOCode(user.LangID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return responseErrors.ErrBadLangID
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.email.SendPasswordResetEmail(user.Email, user.PasswordResetToken, baseURL, lang); err != nil {
|
if err := s.email.SendPasswordResetEmail(user.Email, user.PasswordResetToken, baseURL, lang); err != nil {
|
||||||
@@ -482,7 +477,7 @@ func hashToken(raw string) string {
|
|||||||
func (s *AuthService) generateAccessToken(user *model.Customer) (string, error) {
|
func (s *AuthService) generateAccessToken(user *model.Customer) (string, error) {
|
||||||
_, err := s.GetLangISOCode(user.LangID)
|
_, err := s.GetLangISOCode(user.LangID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", responseErrors.ErrBadLangID
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.CheckIfCountryExists(user.CountryID)
|
err = s.CheckIfCountryExists(user.CountryID)
|
||||||
@@ -508,97 +503,19 @@ func (s *AuthService) generateAccessToken(user *model.Customer) (string, error)
|
|||||||
return token.SignedString([]byte(s.config.JWTSecret))
|
return token.SignedString([]byte(s.config.JWTSecret))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AuthService) UpdateJWTToken(c fiber.Ctx) error {
|
func (s *AuthService) UpdateJWTToken(user *model.Customer) (string, error) {
|
||||||
// Get user ID from JWT claims in context (set by auth middleware)
|
// Update choice and get new access token using AuthService
|
||||||
// claims, ok := c.Locals("jwt_claims").(*JWTClaims)
|
new_access_token, err := s.generateAccessToken(user)
|
||||||
// if !ok || claims == nil {
|
|
||||||
// return c.Status(fiber.StatusUnauthorized).
|
|
||||||
// JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrNotAuthenticated)))
|
|
||||||
// }
|
|
||||||
// fmt.Printf("claims: %v\n", claims)
|
|
||||||
// var user model.Customer
|
|
||||||
// // Find user by ID
|
|
||||||
// if err := s.db.First(&user, claims.UserID).Error; err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
userLocals, ok := c.Locals(constdata.USER_LOCALES_NAME).(*model.UserSession)
|
|
||||||
if !ok {
|
|
||||||
return c.Status(fiber.StatusUnauthorized).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrNotAuthenticated)))
|
|
||||||
}
|
|
||||||
|
|
||||||
user := model.Customer{
|
|
||||||
ID: userLocals.UserID,
|
|
||||||
Email: userLocals.Email,
|
|
||||||
Role: userLocals.Role,
|
|
||||||
LangID: userLocals.LangID,
|
|
||||||
CountryID: userLocals.CountryID,
|
|
||||||
IsActive: userLocals.IsActive,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse language and country_id from query params
|
|
||||||
langIDStr := c.Query("lang_id")
|
|
||||||
|
|
||||||
var langID uint
|
|
||||||
if langIDStr != "" {
|
|
||||||
parsedID, err := strconv.ParseUint(langIDStr, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(fiber.StatusBadRequest).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadLangID)))
|
|
||||||
}
|
|
||||||
langID = uint(parsedID)
|
|
||||||
|
|
||||||
_, err = s.GetLangISOCode(langID)
|
|
||||||
if err != nil {
|
|
||||||
return responseErrors.ErrBadLangID
|
|
||||||
} else {
|
|
||||||
user.LangID = langID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
countryIDStr := c.Query("country_id")
|
|
||||||
|
|
||||||
var countryID uint
|
|
||||||
if countryIDStr != "" {
|
|
||||||
parsedID, err := strconv.ParseUint(countryIDStr, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(fiber.StatusBadRequest).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadCountryID)))
|
|
||||||
}
|
|
||||||
countryID = uint(parsedID)
|
|
||||||
|
|
||||||
err = s.CheckIfCountryExists(countryID)
|
|
||||||
if err != nil {
|
|
||||||
return responseErrors.ErrBadCountryID
|
|
||||||
} else {
|
|
||||||
user.CountryID = countryID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update choice and get new token using AuthService
|
|
||||||
newToken, err := s.generateAccessToken(&user)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(responseErrors.GetErrorStatus(err)).
|
return "", err
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the updated user
|
// Save the updated user
|
||||||
if err := s.db.Save(&user).Error; err != nil {
|
if err := s.db.Save(user).Error; err != nil {
|
||||||
return fmt.Errorf("database error: %w", err)
|
return "", fmt.Errorf("database error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new JWT cookie
|
return new_access_token, nil
|
||||||
cookie := new(fiber.Cookie)
|
|
||||||
cookie.Name = "jwt_token"
|
|
||||||
cookie.Value = newToken
|
|
||||||
cookie.HTTPOnly = true
|
|
||||||
cookie.Secure = true
|
|
||||||
cookie.SameSite = fiber.CookieSameSiteLaxMode
|
|
||||||
|
|
||||||
c.Cookie(cookie)
|
|
||||||
|
|
||||||
return c.JSON(response.Make(&fiber.Map{"token": newToken}, 0, i18n.T_(c, response.Message_OK)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateVerificationToken generates a random verification token
|
// generateVerificationToken generates a random verification token
|
||||||
@@ -623,14 +540,20 @@ func validatePassword(password string) error {
|
|||||||
|
|
||||||
func (s *AuthService) GetLangISOCode(langID uint) (string, error) {
|
func (s *AuthService) GetLangISOCode(langID uint) (string, error) {
|
||||||
var lang string
|
var lang string
|
||||||
|
var err error
|
||||||
|
|
||||||
if langID == 0 { // retrieve the default lang
|
if langID == 0 { // retrieve the default lang
|
||||||
err := db.DB.Table("b2b_language").Where("is_default = ?", 1).Select("iso_code").Scan(&lang).Error
|
err = db.DB.Table("b2b_language").Where("is_default = ?", 1).Select("iso_code").Scan(&lang).Error
|
||||||
return lang, err
|
|
||||||
} else {
|
} else {
|
||||||
err := db.DB.Table("b2b_language").Where("id = ?", langID).Where("active = ?", 1).Select("iso_code").Scan(&lang).Error
|
err = db.DB.Table("b2b_language").Where("id = ?", langID).Where("active = ?", 1).Select("iso_code").Scan(&lang).Error
|
||||||
return lang, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return lang, err
|
||||||
|
} else if lang == "" {
|
||||||
|
return lang, responseErrors.ErrBadLangID
|
||||||
|
}
|
||||||
|
return lang, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AuthService) CheckIfCountryExists(countryID uint) error {
|
func (s *AuthService) CheckIfCountryExists(countryID uint) error {
|
||||||
|
|||||||
@@ -153,7 +153,8 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model.
|
|||||||
Role: model.RoleUser,
|
Role: model.RoleUser,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
EmailVerified: true,
|
EmailVerified: true,
|
||||||
LangID: 2,
|
LangID: 2, // default is english
|
||||||
|
CountryID: 2, // default is England
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.db.Create(&newUser).Error; err != nil {
|
if err := s.db.Create(&newUser).Error; err != nil {
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package listProductsService
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/repos/listProductsRepo"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ListProductsService struct {
|
|
||||||
listProductsRepo listProductsRepo.UIListProductsRepo
|
|
||||||
}
|
|
||||||
|
|
||||||
func New() *ListProductsService {
|
|
||||||
return &ListProductsService{
|
|
||||||
listProductsRepo: listProductsRepo.New(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ListProductsService) GetListing(id_lang uint, p find.Paging, filters *filters.FiltersList) (find.Found[model.ProductInList], error) {
|
|
||||||
var products find.Found[model.ProductInList]
|
|
||||||
|
|
||||||
products, err := s.listProductsRepo.GetListing(id_lang, p, filters)
|
|
||||||
if err != nil {
|
|
||||||
return products, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return products, nil
|
|
||||||
}
|
|
||||||
26
app/service/listService/listService.go
Normal file
26
app/service/listService/listService.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package listService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/repos/listRepo"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListService struct {
|
||||||
|
listRepo listRepo.UIListRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *ListService {
|
||||||
|
return &ListService{
|
||||||
|
listRepo: listRepo.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ListService) ListProducts(id_lang uint, p find.Paging, filters *filters.FiltersList) (find.Found[model.ProductInList], error) {
|
||||||
|
return s.listRepo.ListProducts(id_lang, p, filters)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ListService) ListUsers(id_lang uint, p find.Paging, filters *filters.FiltersList) (find.Found[model.UserInList], error) {
|
||||||
|
return s.listRepo.ListUsers(id_lang, p, filters)
|
||||||
|
}
|
||||||
1
bo/.gitignore
vendored
1
bo/.gitignore
vendored
@@ -13,6 +13,7 @@ dist
|
|||||||
dist-ssr
|
dist-ssr
|
||||||
coverage
|
coverage
|
||||||
*.local
|
*.local
|
||||||
|
/bo/components.d.ts
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
66
bo/components.d.ts
vendored
66
bo/components.d.ts
vendored
@@ -1,66 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
// biome-ignore lint: disable
|
|
||||||
// oxlint-disable
|
|
||||||
// ------
|
|
||||||
// Generated by unplugin-vue-components
|
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
|
||||||
|
|
||||||
export {}
|
|
||||||
|
|
||||||
/* prettier-ignore */
|
|
||||||
declare module 'vue' {
|
|
||||||
export interface GlobalComponents {
|
|
||||||
Cart1: typeof import('./src/components/customer/Cart1.vue')['default']
|
|
||||||
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
|
|
||||||
CategoryMenu: typeof import('./src/components/inner/categoryMenu.vue')['default']
|
|
||||||
CategoryMenuListing: typeof import('./src/components/inner/categoryMenuListing.vue')['default']
|
|
||||||
copy: typeof import('./src/components/inner/categoryMenu copy.vue')['default']
|
|
||||||
Cs_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
|
|
||||||
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.vue')['default']
|
|
||||||
En_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
|
|
||||||
En_TermsAndConditionsView: typeof import('./src/components/terms/en_TermsAndConditionsView.vue')['default']
|
|
||||||
LangSwitch: typeof import('./src/components/inner/langSwitch.vue')['default']
|
|
||||||
Page: typeof import('./src/components/customer/Page.vue')['default']
|
|
||||||
PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default']
|
|
||||||
PageCart: typeof import('./src/components/customer/PageCart.vue')['default']
|
|
||||||
PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default']
|
|
||||||
PageCreateAccount: typeof import('./src/components/customer/PageCreateAccount.vue')['default']
|
|
||||||
PageCustomerData: typeof import('./src/components/customer/PageCustomerData.vue')['default']
|
|
||||||
PageProduct: typeof import('./src/components/customer/PageProduct.vue')['default']
|
|
||||||
PageProductCardFull: typeof import('./src/components/customer/PageProductCardFull.vue')['default']
|
|
||||||
PageProducts: typeof import('./src/components/admin/PageProducts.vue')['default']
|
|
||||||
PageProductsList: typeof import('./src/components/admin/PageProductsList.vue')['default']
|
|
||||||
PageProfileDetails: typeof import('./src/components/customer/PageProfileDetails.vue')['default']
|
|
||||||
PageProfileDetailsAddInfo: typeof import('./src/components/customer/PageProfileDetailsAddInfo.vue')['default']
|
|
||||||
Pl_PrivacyPolicyView: typeof import('./src/components/terms/pl_PrivacyPolicyView.vue')['default']
|
|
||||||
Pl_TermsAndConditionsView: typeof import('./src/components/terms/pl_TermsAndConditionsView.vue')['default']
|
|
||||||
ProductCustomization: typeof import('./src/components/customer/components/ProductCustomization.vue')['default']
|
|
||||||
ProductDetailView: typeof import('./src/components/admin/ProductDetailView.vue')['default']
|
|
||||||
ProductsView: typeof import('./src/components/admin/ProductsView.vue')['default']
|
|
||||||
ProductVariants: typeof import('./src/components/customer/components/ProductVariants.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
|
||||||
ThemeSwitch: typeof import('./src/components/inner/themeSwitch.vue')['default']
|
|
||||||
TopBar: typeof import('./src/components/TopBar.vue')['default']
|
|
||||||
TopBarLogin: typeof import('./src/components/TopBarLogin.vue')['default']
|
|
||||||
UAlert: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Alert.vue')['default']
|
|
||||||
UButton: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Button.vue')['default']
|
|
||||||
UCard: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Card.vue')['default']
|
|
||||||
UCheckbox: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Checkbox.vue')['default']
|
|
||||||
UDrawer: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Drawer.vue')['default']
|
|
||||||
UDropdownMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/DropdownMenu.vue')['default']
|
|
||||||
UForm: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Form.vue')['default']
|
|
||||||
UFormField: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/FormField.vue')['default']
|
|
||||||
UIcon: typeof import('./node_modules/@nuxt/ui/dist/runtime/vue/components/Icon.vue')['default']
|
|
||||||
UInput: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Input.vue')['default']
|
|
||||||
UInputNumber: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/InputNumber.vue')['default']
|
|
||||||
ULink: typeof import('./node_modules/@nuxt/ui/dist/runtime/vue/overrides/vue-router/Link.vue')['default']
|
|
||||||
UModal: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Modal.vue')['default']
|
|
||||||
UNavigationMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/NavigationMenu.vue')['default']
|
|
||||||
UPagination: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Pagination.vue')['default']
|
|
||||||
USelect: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Select.vue')['default']
|
|
||||||
USelectMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/SelectMenu.vue')['default']
|
|
||||||
UTable: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Table.vue')['default']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,10 +3,11 @@ import { useFetchJson } from '@/composable/useFetchJson'
|
|||||||
import LangSwitch from './inner/langSwitch.vue'
|
import LangSwitch from './inner/langSwitch.vue'
|
||||||
import ThemeSwitch from './inner/themeSwitch.vue'
|
import ThemeSwitch from './inner/themeSwitch.vue'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { currentLang } from '@/router/langs'
|
import { currentLang } from '@/router/langs'
|
||||||
import type { LabelTrans, TopMenuItem } from '@/types'
|
import type { LabelTrans, TopMenuItem } from '@/types'
|
||||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
let menu = ref()
|
let menu = ref()
|
||||||
@@ -19,30 +20,43 @@ async function getTopMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
const menuItems = computed(() => transformMenu(menu.value[0].children, currentLang.value?.iso_code))
|
const menuItems = computed(() => transformMenu(menu.value[0].children, currentLang.value?.iso_code))
|
||||||
function transformMenu(items: TopMenuItem[], locale: string | undefined): NavigationMenuItem[] {
|
function transformMenu(items: TopMenuItem[], locale: string | undefined): NavigationMenuItem[] {
|
||||||
|
|
||||||
return items.map((item) => {
|
return items.map((item) => {
|
||||||
let route = {
|
const route: NavigationMenuItem = {
|
||||||
icon: 'i-lucide-house',
|
icon: item.label.icon ? item.label.icon : 'i-lucide-house',
|
||||||
label: item.label.trans[locale as keyof LabelTrans].label,
|
label: item.label.trans[locale as keyof LabelTrans].label,
|
||||||
children: item.children ? transformMenu(item.children, locale) : undefined,
|
children: item.children
|
||||||
|
? transformMenu(item.children, locale)
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
if (item.params?.route) {
|
|
||||||
route = { ...route, ...{ to: { name: item.params.route.name, params: { locale: locale } } } }
|
route.onSelect = () => {
|
||||||
|
const query = {
|
||||||
|
name: item.params.route.name,
|
||||||
|
params: {
|
||||||
|
...(item.params.route.params || {}),
|
||||||
|
locale: currentLang.value?.iso_code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
return route
|
return route
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await getTopMenu()
|
await getTopMenu()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{ menuItems }}
|
<header
|
||||||
<!-- fixed top-0 left-0 right-0 z-50 -->
|
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
|
||||||
<header class="bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
|
<!-- px-4 sm:px-6 lg:px-8 -->
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="container mx-auto px-4">
|
||||||
<div class="flex items-center justify-between h-14">
|
<div class="flex items-center justify-between h-14">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
|
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
|
||||||
@@ -52,49 +66,18 @@ await getTopMenu()
|
|||||||
<span class="font-semibold text-gray-900 dark:text-white">TimeTracker</span>
|
<span class="font-semibold text-gray-900 dark:text-white">TimeTracker</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
<UNavigationMenu :items="menuItems" class="w-full" />
|
<UNavigationMenu :type="'trigger'" :ui="{
|
||||||
|
root: 'justify-center',
|
||||||
<!-- {{ router }} -->
|
list: 'gap-4'
|
||||||
<!-- <RouterLink :to="{ name: 'admin-products' }">
|
}" :items="menuItems" class="w-full"></UNavigationMenu>
|
||||||
products list
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{ name: 'admin-product-detail' }">
|
|
||||||
product detail
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{
|
|
||||||
name: 'customer-product', params: {
|
|
||||||
product_id: '51'
|
|
||||||
}
|
|
||||||
}">
|
|
||||||
Product (51)
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{ name: 'addresses' }">
|
|
||||||
Addresses
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{ name: 'profile-details' }">
|
|
||||||
Customer Data
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{ name: 'cart' }">
|
|
||||||
Cart
|
|
||||||
</RouterLink>
|
|
||||||
<RouterLink :to="{
|
|
||||||
name: 'cart-details', params: {
|
|
||||||
cart_id: '1'
|
|
||||||
}
|
|
||||||
}">
|
|
||||||
Cart details (1)
|
|
||||||
</RouterLink> -->
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Language Switcher -->
|
<!-- Language Switcher -->
|
||||||
<LangSwitch />
|
<LangSwitch />
|
||||||
<!-- Theme Switcher -->
|
<!-- Theme Switcher -->
|
||||||
<ThemeSwitch />
|
<ThemeSwitch />
|
||||||
<!-- Logout Button (only when authenticated) -->
|
<!-- Logout Button (only when authenticated) -->
|
||||||
<button
|
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
|
||||||
v-if="authStore.isAuthenticated"
|
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark)">
|
||||||
@click="authStore.logout()"
|
|
||||||
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark)"
|
|
||||||
>
|
|
||||||
{{ $t('general.logout') }}
|
{{ $t('general.logout') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mx-auto mt-20">
|
<div class="container mx-auto">
|
||||||
<h2
|
<h2
|
||||||
class="font-semibold text-black dark:text-white pb-6 text-2xl">
|
class="font-semibold text-black dark:text-white pb-6 text-2xl">
|
||||||
{{ t('Cart Items') }}
|
{{ t('Cart Items') }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mx-auto mt-20">
|
<div class="container mx-auto">
|
||||||
<div class="flex flex-col gap-5 mb-6">
|
<div class="flex flex-col gap-5 mb-6">
|
||||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Addresses') }}</h1>
|
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Addresses') }}</h1>
|
||||||
<div class="flex md:flex-row flex-col justify-between items-start md:items-center gap-5 md:gap-0">
|
<div class="flex md:flex-row flex-col justify-between items-start md:items-center gap-5 md:gap-0">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mx-auto mt-20 flex flex-col gap-5 md:gap-10">
|
<div class="container mx-auto flex flex-col gap-5 md:gap-10">
|
||||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Cart') }}</h1>
|
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Cart') }}</h1>
|
||||||
<div class="flex flex-col lg:flex-row gap-5 md:gap-10">
|
<div class="flex flex-col lg:flex-row gap-5 md:gap-10">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
|
|||||||
9
bo/src/components/customer/PageOrders.vue
Normal file
9
bo/src/components/customer/PageOrders.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<component :is="Default || 'div'">
|
||||||
|
Orders page
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Default from '@/layouts/default.vue'
|
||||||
|
</script>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mt-20 mx-auto">
|
<div class="container mx-auto">
|
||||||
<div class="flex md:flex-row flex-col justify-between gap-8 my-6">
|
<div class="flex md:flex-row flex-col justify-between gap-8 my-6">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="bg-gray-100 dark:bg-gray-800 rounded-lg p-8 flex items-center justify-center min-h-[300px] ">
|
<div class="bg-gray-100 dark:bg-gray-800 rounded-lg p-8 flex items-center justify-center min-h-[300px] ">
|
||||||
|
|||||||
430
bo/src/components/customer/PageProducts.vue
Normal file
430
bo/src/components/customer/PageProducts.vue
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
<template>
|
||||||
|
<suspense>
|
||||||
|
<component :is="Default || 'div'">
|
||||||
|
<div class="container mx-auto">
|
||||||
|
<!-- <UNavigationMenu orientation="vertical" :items="listing" class="data-[orientation=vertical]:w-48">
|
||||||
|
<template #item="{ item, active }">
|
||||||
|
<div class="flex items-center gap-2 px-3 py-2">
|
||||||
|
<UIcon name="i-heroicons-book-open" />
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UNavigationMenu> -->
|
||||||
|
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">Products</h1>
|
||||||
|
<div v-if="loading" class="text-center py-8">
|
||||||
|
<span class="text-gray-600 dark:text-gray-400">Loading products...</span>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error" class="mb-4 p-3 bg-red-100 text-red-700 rounded">
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="overflow-x-auto">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<CategoryMenuListing />
|
||||||
|
<UTable :data="productsList" :columns="columns" class="flex-1">
|
||||||
|
<template #expanded="{ row }">
|
||||||
|
<UTable :data="productsList.slice(0, 3)" :columns="columnsChild" :ui="{
|
||||||
|
thead: 'hidden'
|
||||||
|
}" />
|
||||||
|
</template>
|
||||||
|
</UTable>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center items-center py-8">
|
||||||
|
<UPagination v-model:page="page" :total="total" :page-size="perPage" />
|
||||||
|
</div>
|
||||||
|
<div v-if="productsList.length === 0" class="text-center py-8 text-gray-500 dark:text-gray-400">
|
||||||
|
No products found
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</component>
|
||||||
|
</suspense>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch, h, resolveComponent, computed } from 'vue'
|
||||||
|
import { useFetchJson } from '@/composable/useFetchJson'
|
||||||
|
import Default from '@/layouts/default.vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import type { TableColumn } from '@nuxt/ui'
|
||||||
|
import CategoryMenuListing from '../inner/categoryMenuListing.vue'
|
||||||
|
|
||||||
|
interface Product {
|
||||||
|
reference: number
|
||||||
|
product_id: number
|
||||||
|
name: string
|
||||||
|
image_link: string
|
||||||
|
link_rewrite: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const page = computed({
|
||||||
|
get: () => Number(route.query.page) || 1,
|
||||||
|
set: (val: number) => {
|
||||||
|
router.push({
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
page: val
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const sortField = computed({
|
||||||
|
get: () => [
|
||||||
|
route.query.sort as string | undefined,
|
||||||
|
route.query.direction as 'asc' | 'desc' | undefined
|
||||||
|
],
|
||||||
|
|
||||||
|
set: ([sort]: [string, 'asc' | 'desc']) => {
|
||||||
|
const currentSort = route.query.sort as string | undefined
|
||||||
|
const currentDirection = route.query.direction as 'asc' | 'desc' | undefined
|
||||||
|
|
||||||
|
let query = { ...route.query }
|
||||||
|
|
||||||
|
if (currentSort === sort) {
|
||||||
|
if (currentDirection === 'asc') {
|
||||||
|
query.direction = 'desc'
|
||||||
|
} else if (currentDirection === 'desc') {
|
||||||
|
delete query.sort
|
||||||
|
delete query.direction
|
||||||
|
} else {
|
||||||
|
query.direction = 'asc'
|
||||||
|
query.sort = sort
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
query.sort = sort
|
||||||
|
query.direction = 'asc'
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push({ query })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const perPage = ref(15)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
|
interface ApiResponse {
|
||||||
|
message: string
|
||||||
|
items: Product[]
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const productsList = ref<Product[]>([])
|
||||||
|
const loading = ref(true)
|
||||||
|
const error = ref<string | null>(null)
|
||||||
|
const filters = computed<Record<string, string>>({
|
||||||
|
get: () => {
|
||||||
|
const q = { ...route.query }
|
||||||
|
delete q.page
|
||||||
|
delete q.sort
|
||||||
|
delete q.direction
|
||||||
|
return q as Record<string, string>
|
||||||
|
},
|
||||||
|
set: (val) => {
|
||||||
|
const baseQuery = { ...route.query }
|
||||||
|
|
||||||
|
Object.keys(baseQuery).forEach(key => {
|
||||||
|
if (!['page', 'sort', 'direction'].includes(key)) {
|
||||||
|
delete baseQuery[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.push({
|
||||||
|
query: {
|
||||||
|
...baseQuery,
|
||||||
|
...val,
|
||||||
|
page: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function debounce(fn: Function, delay = 400) {
|
||||||
|
let t: any
|
||||||
|
return (...args: any[]) => {
|
||||||
|
clearTimeout(t)
|
||||||
|
t = setTimeout(() => fn(...args), delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateFilter = debounce((columnId: string, val: string) => {
|
||||||
|
const newFilters = { ...filters.value }
|
||||||
|
|
||||||
|
if (val) newFilters[columnId] = val
|
||||||
|
else delete newFilters[columnId]
|
||||||
|
|
||||||
|
filters.value = newFilters
|
||||||
|
}, 400)
|
||||||
|
|
||||||
|
async function fetchProductList() {
|
||||||
|
loading.value = true
|
||||||
|
error.value = null
|
||||||
|
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
|
||||||
|
Object.entries(route.query).forEach(([key, value]) => {
|
||||||
|
if (value) params.append(key, String(value))
|
||||||
|
})
|
||||||
|
|
||||||
|
const url = `/api/v1/restricted/list-products/get-listing?${params}`
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await useFetchJson<ApiResponse>(url)
|
||||||
|
productsList.value = response.items || []
|
||||||
|
total.value = response.count || 0
|
||||||
|
} catch (e: unknown) {
|
||||||
|
error.value = e instanceof Error ? e.message : 'Failed to load products'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToProduct(productId: number) {
|
||||||
|
router.push({
|
||||||
|
name: 'product-detail',
|
||||||
|
params: { id: productId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedCount = ref({
|
||||||
|
product_id: null,
|
||||||
|
count: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
function getIcon(name: string) {
|
||||||
|
if (sortField.value[0] === name) {
|
||||||
|
if (sortField.value[1] === 'asc') return 'i-lucide-arrow-up-narrow-wide'
|
||||||
|
if (sortField.value[1] === 'desc') return 'i-lucide-arrow-down-wide-narrow'
|
||||||
|
}
|
||||||
|
return 'i-lucide-arrow-up-down'
|
||||||
|
}
|
||||||
|
|
||||||
|
const UInputNumber = resolveComponent('UInputNumber')
|
||||||
|
const UInput = resolveComponent('UInput')
|
||||||
|
const UButton = resolveComponent('UButton')
|
||||||
|
const UIcon = resolveComponent('UIcon')
|
||||||
|
|
||||||
|
const columns: TableColumn<Payment>[] = [
|
||||||
|
{
|
||||||
|
id: 'expand',
|
||||||
|
cell: ({ row }) =>
|
||||||
|
h(UButton, {
|
||||||
|
color: 'neutral',
|
||||||
|
variant: 'ghost',
|
||||||
|
icon: 'i-lucide-chevron-down',
|
||||||
|
square: true,
|
||||||
|
'aria-label': 'Expand',
|
||||||
|
ui: {
|
||||||
|
leadingIcon: [
|
||||||
|
'transition-transform',
|
||||||
|
row.getIsExpanded() ? 'duration-200 rotate-180' : ''
|
||||||
|
]
|
||||||
|
},
|
||||||
|
onClick: () => row.toggleExpanded()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'product_id',
|
||||||
|
header: ({ column }) => {
|
||||||
|
return h('div', { class: 'flex flex-col gap-1' }, [
|
||||||
|
h('div', {
|
||||||
|
class: 'flex items-center gap-2 cursor-pointer',
|
||||||
|
onClick: () => {
|
||||||
|
sortField.value = ['product_id', 'asc']
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
h('span', 'ID'),
|
||||||
|
h(UIcon, {
|
||||||
|
name: getIcon('product_id')
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
|
||||||
|
h(UInput, {
|
||||||
|
placeholder: 'Search...',
|
||||||
|
modelValue: filters.value[column.id] ?? '',
|
||||||
|
'onUpdate:modelValue': (val: string) => {
|
||||||
|
updateFilter(column.id, val)
|
||||||
|
},
|
||||||
|
size: 'xs'
|
||||||
|
})
|
||||||
|
])
|
||||||
|
},
|
||||||
|
// header: '#',
|
||||||
|
cell: ({ row }) => `#${row.getValue('product_id') as number}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'image_link',
|
||||||
|
header: 'Image',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h('img', {
|
||||||
|
src: row.getValue('image_link') as string,
|
||||||
|
style: 'width:40px;height:40px;object-fit:cover;'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'name',
|
||||||
|
header: ({ column }) => {
|
||||||
|
return h('div', { class: 'flex flex-col gap-1' }, [
|
||||||
|
h('div', {
|
||||||
|
class: 'flex items-center gap-2 cursor-pointer',
|
||||||
|
onClick: () => {
|
||||||
|
sortField.value = ['name', 'asc']
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
h('span', 'Name'),
|
||||||
|
h(UIcon, {
|
||||||
|
name: getIcon('name')
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
|
||||||
|
h(UInput, {
|
||||||
|
placeholder: 'Search...',
|
||||||
|
modelValue: filters.value[column.id] ?? '',
|
||||||
|
'onUpdate:modelValue': (val: string) => {
|
||||||
|
updateFilter(column.id, val)
|
||||||
|
},
|
||||||
|
size: 'xs'
|
||||||
|
})
|
||||||
|
])
|
||||||
|
},
|
||||||
|
cell: ({ row }) => row.getValue('name') as string,
|
||||||
|
filterFn: (row, columnId, value) => {
|
||||||
|
const name = row.getValue(columnId) as string
|
||||||
|
return name.toLowerCase().includes(value.toLowerCase())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'quantity',
|
||||||
|
header: ({ column }) => {
|
||||||
|
return h('div', { class: 'flex flex-col gap-1' }, [
|
||||||
|
h('div', {
|
||||||
|
class: 'flex items-center gap-2 cursor-pointer',
|
||||||
|
onClick: () => {
|
||||||
|
sortField.value = ['quantity', 'asc']
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
h('span', 'In stock'),
|
||||||
|
h(UIcon, {
|
||||||
|
name: getIcon('quantity')
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
},
|
||||||
|
cell: ({ row }) => row.getValue('quantity') as number
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'count',
|
||||||
|
header: 'Count',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h(UInputNumber, {
|
||||||
|
modelValue: selectedCount.value.product_id === row.original.product_id ? selectedCount.value.count : 0,
|
||||||
|
'onUpdate:modelValue': (val: number) => {
|
||||||
|
if (val)
|
||||||
|
selectedCount.value = {
|
||||||
|
product_id: row.original.product_id,
|
||||||
|
count: val
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedCount.value = {
|
||||||
|
product_id: null,
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: row.original.quantity
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'count',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h(UButton, {
|
||||||
|
onClick: () => {
|
||||||
|
console.log('Clicked', row.original)
|
||||||
|
},
|
||||||
|
color: selectedCount.value.product_id !== row.original.product_id ? 'info' : 'primary',
|
||||||
|
disabled: selectedCount.value.product_id !== row.original.product_id,
|
||||||
|
variant: 'solid'
|
||||||
|
}, 'Add to cart')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columnsChild: TableColumn<Payment>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: 'product_id',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => `#${row.getValue('product_id') as number}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'image_link',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h('img', {
|
||||||
|
src: row.getValue('image_link') as string,
|
||||||
|
style: 'width:40px;height:40px;object-fit:cover;'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'name',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => row.getValue('name') as string
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'quantity',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => row.getValue('quantity') as number
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'count',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h(UInputNumber, {
|
||||||
|
modelValue: selectedCount.value.product_id === row.original.product_id ? selectedCount.value.count : 0,
|
||||||
|
'onUpdate:modelValue': (val: number) => {
|
||||||
|
if (val)
|
||||||
|
selectedCount.value = {
|
||||||
|
product_id: row.original.product_id,
|
||||||
|
count: val
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedCount.value = {
|
||||||
|
product_id: null,
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: row.original.quantity
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'count',
|
||||||
|
header: '',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return h(UButton, {
|
||||||
|
onClick: () => {
|
||||||
|
console.log('Clicked', row.original)
|
||||||
|
},
|
||||||
|
color: selectedCount.value.product_id !== row.original.product_id ? 'info' : 'primary',
|
||||||
|
disabled: selectedCount.value.product_id !== row.original.product_id,
|
||||||
|
variant: 'solid'
|
||||||
|
}, 'Add to cart')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.query,
|
||||||
|
() => {
|
||||||
|
fetchProductList()
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
</script>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mx-auto mt-20">
|
<div class="container mx-auto">
|
||||||
<div class="flex flex-col gap-5 mb-6">
|
<div class="flex flex-col gap-5 mb-6">
|
||||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Customer Data') }}</h1>
|
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Customer Data') }}</h1>
|
||||||
|
|
||||||
|
|||||||
@@ -1,106 +1,114 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="container mx-auto mt-20">
|
<div class="container mx-auto">
|
||||||
<div class="max-w-2xl mx-auto">
|
<div class="max-w-2xl mx-auto">
|
||||||
<div class="flex flex-col gap-5 mb-6">
|
<div class="flex flex-col gap-5 mb-6">
|
||||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Create Account') }}</h1>
|
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Create Account') }}</h1>
|
||||||
<div
|
<div
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) p-4">
|
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) p-4">
|
||||||
<UForm @submit.prevent="saveAccount" :validate="validate" class="space-y-6">
|
<UForm @submit.prevent="saveAccount" :validate="validate" class="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
|
<h2
|
||||||
<UIcon name="mdi:domain"
|
class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
|
||||||
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
<UIcon name="mdi:domain"
|
||||||
{{ t('Company Information') }}
|
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
||||||
</h2>
|
{{ t('Company Information') }}
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
</h2>
|
||||||
<div class="md:col-span-2">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
<div class="md:col-span-2">
|
||||||
t('Company Name') }} *</label>
|
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
||||||
<UInput v-model="formData.companyName" :placeholder="t('Enter company name')"
|
t('Company Name') }} *</label>
|
||||||
name="companyName" class="w-full" />
|
<UInput v-model="formData.companyName" :placeholder="t('Enter company name')"
|
||||||
</div>
|
name="companyName" class="w-full" />
|
||||||
<div class="md:col-span-2">
|
</div>
|
||||||
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
<div class="md:col-span-2">
|
||||||
t('Company Email') }} *</label>
|
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
||||||
<UInput v-model="formData.companyEmail" type="email"
|
t('Company Email') }} *</label>
|
||||||
:placeholder="t('Enter company email')" name="companyEmail" class="w-full" />
|
<UInput v-model="formData.companyEmail" type="email"
|
||||||
</div>
|
:placeholder="t('Enter company email')" name="companyEmail"
|
||||||
<div>
|
class="w-full" />
|
||||||
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
</div>
|
||||||
t('REGON') }}</label>
|
<div>
|
||||||
<UInput v-model="formData.regon" :placeholder="t('Enter REGON')" name="regon"
|
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
||||||
class="w-full" />
|
t('REGON') }}</label>
|
||||||
</div>
|
<UInput v-model="formData.regon" :placeholder="t('Enter REGON')" name="regon"
|
||||||
<div>
|
class="w-full" />
|
||||||
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{ t('NIP')
|
</div>
|
||||||
}}</label>
|
<div>
|
||||||
<UInput v-model="formData.nip" :placeholder="t('Enter NIP')" name="nip"
|
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
||||||
class="w-full" />
|
t('NIP')
|
||||||
</div>
|
}}</label>
|
||||||
<div>
|
<UInput v-model="formData.nip" :placeholder="t('Enter NIP')" name="nip"
|
||||||
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{ t('VAT')
|
class="w-full" />
|
||||||
}}</label>
|
</div>
|
||||||
<UInput v-model="formData.vat" :placeholder="t('Enter VAT')" name="vat"
|
<div>
|
||||||
class="w-full" />
|
<label class="block text-sm font-medium text-black dark:text-white mb-1">{{
|
||||||
|
t('VAT')
|
||||||
|
}}</label>
|
||||||
|
<UInput v-model="formData.vat" :placeholder="t('Enter VAT')" name="vat"
|
||||||
|
class="w-full" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
<div>
|
<h2
|
||||||
<h2 class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
|
class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
|
||||||
<UIcon name="mdi:map-marker"
|
<UIcon name="mdi:map-marker"
|
||||||
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
||||||
{{ t('Select Addresses') }}
|
{{ t('Select Addresses') }}
|
||||||
</h2>
|
</h2>
|
||||||
<div
|
<div class="bg-(--second-light) dark:bg-(--main-dark)">
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark)">
|
<div class="mb-4">
|
||||||
<div class="mb-4">
|
<UInput v-model="addressSearchQuery" type="text"
|
||||||
<UInput v-model="addressSearchQuery" type="text" :placeholder="t('Search address')"
|
:placeholder="t('Search address')"
|
||||||
class="w-full bg-white dark:bg-(--black) text-black dark:text-white" />
|
class="w-full bg-white dark:bg-(--black) text-black dark:text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="addressStore.filteredAddresses.length > 0" class="space-y-3">
|
<div v-if="addressStore.filteredAddresses.length > 0" class="space-y-3">
|
||||||
<label v-for="address in addressStore.filteredAddresses" :key="address.id"
|
<label v-for="address in addressStore.filteredAddresses" :key="address.id"
|
||||||
class="flex items-start gap-3 p-4 border rounded-lg cursor-pointer transition-colors"
|
class="flex items-start gap-3 p-4 border rounded-lg cursor-pointer transition-colors"
|
||||||
:class="cartStore.selectedAddressId === address.id
|
:class="cartStore.selectedAddressId === address.id
|
||||||
? 'border-(--accent-blue-light) dark:border-(--accent-blue-dark) bg-blue-50 dark:bg-blue-900/20'
|
? 'border-(--accent-blue-light) dark:border-(--accent-blue-dark) bg-blue-50 dark:bg-blue-900/20'
|
||||||
: 'border-(--border-light) dark:border-(--border-dark) hover:border-gray-400'">
|
: 'border-(--border-light) dark:border-(--border-dark) hover:border-gray-400'">
|
||||||
<input type="radio" :value="address.id" v-model="selectedAddress"
|
<input type="radio" :value="address.id" v-model="selectedAddress"
|
||||||
class="mt-1 w-4 h-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
class="mt-1 w-4 h-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<p class="text-black dark:text-white font-medium">{{ address.street }}</p>
|
<p class="text-black dark:text-white font-medium">{{ address.street }}
|
||||||
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ address.zipCode }},
|
</p>
|
||||||
{{ address.city }}</p>
|
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ address.zipCode
|
||||||
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ address.country }}
|
}},
|
||||||
</p>
|
{{ address.city }}</p>
|
||||||
</div>
|
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ address.country
|
||||||
</label>
|
}}
|
||||||
</div>
|
</p>
|
||||||
<div v-else class="text-center py-6">
|
</div>
|
||||||
<UIcon name="mdi:map-marker-outline" class="text-4xl text-gray-400 mb-2" />
|
</label>
|
||||||
<p class="text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</p>
|
</div>
|
||||||
<RouterLink :to="{ name: 'addresses' }"
|
<div v-else class="text-center py-6">
|
||||||
class="inline-block mt-2 text-(--accent-blue-light) dark:text-(--accent-blue-dark) hover:underline">
|
<UIcon name="mdi:map-marker-outline" class="text-4xl text-gray-400 mb-2" />
|
||||||
{{ t('Add Address') }}
|
<p class="text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</p>
|
||||||
</RouterLink>
|
<RouterLink :to="{ name: 'addresses' }"
|
||||||
|
class="inline-block mt-2 text-(--accent-blue-light) dark:text-(--accent-blue-dark) hover:underline">
|
||||||
|
{{ t('Add Address') }}
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="flex justify-end gap-3 pt-4">
|
||||||
<div class="flex justify-end gap-3 pt-4">
|
<UButton variant="outline" color="neutral" @click="goBack"
|
||||||
<UButton variant="outline" color="neutral" @click="goBack"
|
class="text-black dark:text-white">
|
||||||
class="text-black dark:text-white">
|
{{ t('Cancel') }}
|
||||||
{{ t('Cancel') }}
|
</UButton>
|
||||||
</UButton>
|
<UButton type="submit" color="primary"
|
||||||
<UButton type="submit" color="primary"
|
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) hover:bg-(--accent-blue-dark) dark:hover:bg-(--accent-blue-light)">
|
||||||
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) hover:bg-(--accent-blue-dark) dark:hover:bg-(--accent-blue-light)">
|
<UIcon name="mdi:content-save" />
|
||||||
<UIcon name="mdi:content-save" />
|
{{ t('Save') }}
|
||||||
{{ t('Save') }}
|
</UButton>
|
||||||
</UButton>
|
</div>
|
||||||
</div>
|
</UForm>
|
||||||
</UForm>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -170,7 +178,7 @@ function saveAccount() {
|
|||||||
vat: formData.value.vat,
|
vat: formData.value.vat,
|
||||||
companyAddressId: formData.value.companyAddressId,
|
companyAddressId: formData.value.companyAddressId,
|
||||||
billingAddressId: formData.value.billingAddressId,
|
billingAddressId: formData.value.billingAddressId,
|
||||||
companyAddress : ''
|
companyAddress: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
router.push({ name: 'profile-details' })
|
router.push({ name: 'profile-details' })
|
||||||
|
|||||||
9
bo/src/components/customer/PageStatistic.vue
Normal file
9
bo/src/components/customer/PageStatistic.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<component :is="Default || 'div'">
|
||||||
|
Statistic page
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Default from '@/layouts/default.vue'
|
||||||
|
</script>
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
{{ locale }}
|
<USelectMenu v-model="locale" :items="langs"
|
||||||
<USelectMenu v-model="locale" :items="langs" class="w-40 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm hover:none!"
|
class="w-40 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm hover:none!" valueKey="iso_code"
|
||||||
valueKey="iso_code" :searchInput="false">
|
:searchInput="false">
|
||||||
<template #default="{ modelValue }">
|
<template #default="{ modelValue }">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<span class="text-md dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.flag}}</span>
|
<!-- <span class="text-md dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.flag}}</span> -->
|
||||||
<span class="font-medium dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.name}}</span>
|
<span class="font-medium dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.name}}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #item-leading="{ item }">
|
<template #item-leading="{ item }">
|
||||||
<div class="flex items-center rounded-md cursor-pointer transition-colors">
|
<div class="flex items-center rounded-md cursor-pointer transition-colors">
|
||||||
<span class="text-md ">{{ item.flag }}</span>
|
<!-- <span class="text-md ">{{ item.flag }}</span> -->
|
||||||
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
|
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -23,6 +23,7 @@ import { useRouter, useRoute } from 'vue-router'
|
|||||||
import { useCookie } from '@/composable/useCookie'
|
import { useCookie } from '@/composable/useCookie'
|
||||||
import { computed, watch } from 'vue'
|
import { computed, watch } from 'vue'
|
||||||
import { i18n } from '@/plugins/02_i18n'
|
import { i18n } from '@/plugins/02_i18n'
|
||||||
|
import { useFetchJson } from '@/composable/useFetchJson'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
@@ -50,9 +51,22 @@ const locale = computed({
|
|||||||
router.replace({ path: '/' + value + currentPath, query: route.query })
|
router.replace({ path: '/' + value + currentPath, query: route.query })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeLang()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function changeLang() {
|
||||||
|
try {
|
||||||
|
const { items } = await useFetchJson('/api/v1/public/auth/update-choice', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.params.locale,
|
() => route.params.locale,
|
||||||
(newLocale) => {
|
(newLocale) => {
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import TopBar from '@/components/TopBar.vue';
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen grid grid-rows-[auto_1fr_auto]">
|
<div class="h-screen grid grid-rows-[auto_1fr_auto]">
|
||||||
<main class="p-10">
|
<main class="pt-20 pb-10">
|
||||||
<TopBar/>
|
<TopBar />
|
||||||
<slot></slot>
|
<div class="container mx-auto px-4">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -49,6 +49,42 @@ const router = createRouter({
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const viewModules = import.meta.glob('/src/views/**/*.vue')
|
||||||
|
const componentModules = import.meta.glob('/src/components/**/*.vue')
|
||||||
|
|
||||||
|
async function setRoutes() {
|
||||||
|
const routes = await getRoutes()
|
||||||
|
|
||||||
|
for (const item of routes) {
|
||||||
|
const componentName = item.component
|
||||||
|
const [, folder] = componentName.split('/')
|
||||||
|
const componentPath = `/src${componentName}`
|
||||||
|
console.log(componentPath);
|
||||||
|
|
||||||
|
|
||||||
|
let modules =
|
||||||
|
folder === 'views' ? viewModules : componentModules
|
||||||
|
|
||||||
|
const importer = modules[componentPath]
|
||||||
|
|
||||||
|
if (!importer) {
|
||||||
|
console.error('Component not found:', componentPath)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const importedComponent = (await importer()).default
|
||||||
|
|
||||||
|
router.addRoute('locale', {
|
||||||
|
path: item.path,
|
||||||
|
component: importedComponent,
|
||||||
|
name: item.name,
|
||||||
|
meta: item.meta ? JSON.parse(item.meta) : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await setRoutes()
|
||||||
|
|
||||||
router.beforeEach((to, from) => {
|
router.beforeEach((to, from) => {
|
||||||
const locale = to.params.locale as string
|
const locale = to.params.locale as string
|
||||||
const localeLang = langs.find((x) => x.iso_code === locale)
|
const localeLang = langs.find((x) => x.iso_code === locale)
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import type { MenuItem, Route } from "@/types/menu";
|
|||||||
|
|
||||||
export const getMenu = async () => {
|
export const getMenu = async () => {
|
||||||
const resp = await useFetchJson<MenuItem>('/api/v1/restricted/menu/get-menu');
|
const resp = await useFetchJson<MenuItem>('/api/v1/restricted/menu/get-menu');
|
||||||
|
|
||||||
return resp.items.children
|
return resp.items.children
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -13,5 +11,4 @@ export const getRoutes = async () => {
|
|||||||
const resp = await useFetchJson<Route[]>('/api/v1/public/menu/get-routes');
|
const resp = await useFetchJson<Route[]>('/api/v1/public/menu/get-routes');
|
||||||
|
|
||||||
return resp.items
|
return resp.items
|
||||||
|
|
||||||
}
|
}
|
||||||
11
bo/src/types/menu.d.ts
vendored
11
bo/src/types/menu.d.ts
vendored
@@ -31,13 +31,14 @@ export interface TopMenuItem {
|
|||||||
|
|
||||||
export interface Label {
|
export interface Label {
|
||||||
label: string
|
label: string
|
||||||
trans:LabelTrans
|
trans: LabelTrans
|
||||||
|
icon?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LabelTrans{
|
export interface LabelTrans {
|
||||||
pl:LabelItem
|
pl: LabelItem
|
||||||
en:LabelItem
|
en: LabelItem
|
||||||
de: LabelItem
|
de: LabelItem
|
||||||
}
|
}
|
||||||
export interface LabelItem {
|
export interface LabelItem {
|
||||||
label: string
|
label: string
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: "{{bas_url}}/restricted/list-products/get-listing?p=1&elems=30&sort=product_id,asc&category_id_in=243&reference=~62"
|
url: "{{bas_url}}/restricted/list/list-products?p=1&elems=30&sort=product_id,asc&category_id_in=243&reference=~62"
|
||||||
params:
|
params:
|
||||||
- name: p
|
- name: p
|
||||||
value: "1"
|
value: "1"
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ http:
|
|||||||
type: json
|
type: json
|
||||||
data: |-
|
data: |-
|
||||||
{
|
{
|
||||||
"q": "kinder",
|
"q": "mat",
|
||||||
"limit": 50,
|
"limit": 50,
|
||||||
"offset": 0,
|
"offset": 0,
|
||||||
// "filter": "'attr.10'= 71",
|
"filter": "'category_ids'= 10",
|
||||||
"facets":["category_ids", "price"]
|
// "facets":["category_ids", "price"]
|
||||||
// "facets": ["category_ids", "attr", "feat", "price"]
|
"facets": ["category_ids", "attr", "feat", "price"]
|
||||||
}
|
}
|
||||||
auth:
|
auth:
|
||||||
type: bearer
|
type: bearer
|
||||||
|
|||||||
9
bruno/b2b-daniel/.gitignore
vendored
Normal file
9
bruno/b2b-daniel/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Secrets
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
15
bruno/b2b-daniel/add-new-cart.yml
Normal file
15
bruno/b2b-daniel/add-new-cart.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: add-new-cart
|
||||||
|
type: http
|
||||||
|
seq: 11
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/add-new-cart
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
25
bruno/b2b-daniel/add-product-to-cart (1).yml
Normal file
25
bruno/b2b-daniel/add-product-to-cart (1).yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
info:
|
||||||
|
name: add-product-to-cart (1)
|
||||||
|
type: http
|
||||||
|
seq: 16
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&amount=1
|
||||||
|
params:
|
||||||
|
- name: cart_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: product_id
|
||||||
|
value: "51"
|
||||||
|
type: query
|
||||||
|
- name: amount
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
28
bruno/b2b-daniel/add-product-to-cart.yml
Normal file
28
bruno/b2b-daniel/add-product-to-cart.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
info:
|
||||||
|
name: add-product-to-cart
|
||||||
|
type: http
|
||||||
|
seq: 15
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&product_attribute_id=1115&amount=1
|
||||||
|
params:
|
||||||
|
- name: cart_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: product_id
|
||||||
|
value: "51"
|
||||||
|
type: query
|
||||||
|
- name: product_attribute_id
|
||||||
|
value: "1115"
|
||||||
|
type: query
|
||||||
|
- name: amount
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
22
bruno/b2b-daniel/change-cart-name.yml
Normal file
22
bruno/b2b-daniel/change-cart-name.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
info:
|
||||||
|
name: change-cart-name
|
||||||
|
type: http
|
||||||
|
seq: 12
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/change-cart-name?cart_id=1&new_name=test
|
||||||
|
params:
|
||||||
|
- name: cart_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: new_name
|
||||||
|
value: test
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
15
bruno/b2b-daniel/create-index.yml
Normal file
15
bruno/b2b-daniel/create-index.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: create-index
|
||||||
|
type: http
|
||||||
|
seq: 7
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/meili-search/create-index
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
17
bruno/b2b-daniel/get-indexes.yml
Normal file
17
bruno/b2b-daniel/get-indexes.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
info:
|
||||||
|
name: get-indexes
|
||||||
|
type: http
|
||||||
|
seq: 9
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:7700/indexes
|
||||||
|
auth:
|
||||||
|
type: bearer
|
||||||
|
token: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
19
bruno/b2b-daniel/get-menu.yml
Normal file
19
bruno/b2b-daniel/get-menu.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
info:
|
||||||
|
name: get-menu
|
||||||
|
type: http
|
||||||
|
seq: 5
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/menu/get-menu?lang_id=1
|
||||||
|
params:
|
||||||
|
- name: lang_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
15
bruno/b2b-daniel/get_countries.yml
Normal file
15
bruno/b2b-daniel/get_countries.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: get_countries
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/langs-and-countries/get-countries
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
21
bruno/b2b-daniel/list-products.yml
Normal file
21
bruno/b2b-daniel/list-products.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
info:
|
||||||
|
name: list-products
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/list/list-products?p=1&elems=10
|
||||||
|
params:
|
||||||
|
- name: p
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: elems
|
||||||
|
value: "10"
|
||||||
|
type: query
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
21
bruno/b2b-daniel/list-users.yml
Normal file
21
bruno/b2b-daniel/list-users.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
info:
|
||||||
|
name: list-users
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/list/list-users?p=1&elems=10
|
||||||
|
params:
|
||||||
|
- name: p
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: elems
|
||||||
|
value: "10"
|
||||||
|
type: query
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
21
bruno/b2b-daniel/opencollection.yml
Normal file
21
bruno/b2b-daniel/opencollection.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
opencollection: 1.0.0
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: b2b-daniel
|
||||||
|
config:
|
||||||
|
proxy:
|
||||||
|
inherit: true
|
||||||
|
config:
|
||||||
|
protocol: http
|
||||||
|
hostname: ""
|
||||||
|
port: ""
|
||||||
|
auth:
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
bypassProxy: ""
|
||||||
|
bundled: false
|
||||||
|
extensions:
|
||||||
|
bruno:
|
||||||
|
ignore:
|
||||||
|
- node_modules
|
||||||
|
- .git
|
||||||
17
bruno/b2b-daniel/remove-index.yml
Normal file
17
bruno/b2b-daniel/remove-index.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
info:
|
||||||
|
name: remove-index
|
||||||
|
type: http
|
||||||
|
seq: 8
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: DELETE
|
||||||
|
url: http://localhost:7700/indexes/meili_products_shop1_lang1
|
||||||
|
auth:
|
||||||
|
type: bearer
|
||||||
|
token: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
19
bruno/b2b-daniel/retrieve-cart.yml
Normal file
19
bruno/b2b-daniel/retrieve-cart.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
info:
|
||||||
|
name: retrieve-cart
|
||||||
|
type: http
|
||||||
|
seq: 14
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/retrieve-cart?cart_id=3
|
||||||
|
params:
|
||||||
|
- name: cart_id
|
||||||
|
value: "3"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
15
bruno/b2b-daniel/retrieve-carts-info.yml
Normal file
15
bruno/b2b-daniel/retrieve-carts-info.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: retrieve-carts-info
|
||||||
|
type: http
|
||||||
|
seq: 13
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/carts/retrieve-carts-info
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
31
bruno/b2b-daniel/search.yml
Normal file
31
bruno/b2b-daniel/search.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
info:
|
||||||
|
name: search
|
||||||
|
type: http
|
||||||
|
seq: 10
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/meili-search/search?query=w&limit=4&id_category=0&price_lower_bound=60.0&price_upper_bound=70.0
|
||||||
|
params:
|
||||||
|
- name: query
|
||||||
|
value: w
|
||||||
|
type: query
|
||||||
|
- name: limit
|
||||||
|
value: "4"
|
||||||
|
type: query
|
||||||
|
- name: id_category
|
||||||
|
value: "0"
|
||||||
|
type: query
|
||||||
|
- name: price_lower_bound
|
||||||
|
value: "60.0"
|
||||||
|
type: query
|
||||||
|
- name: price_upper_bound
|
||||||
|
value: "70.0"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
15
bruno/b2b-daniel/test.yml
Normal file
15
bruno/b2b-daniel/test.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: test
|
||||||
|
type: http
|
||||||
|
seq: 6
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/meili-search/test
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
22
bruno/b2b-daniel/update-choice.yml
Normal file
22
bruno/b2b-daniel/update-choice.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
info:
|
||||||
|
name: update-choice
|
||||||
|
type: http
|
||||||
|
seq: 3
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
url: http://localhost:3000/api/v1/public/auth/update-choice?lang_id=0&country_id=1
|
||||||
|
params:
|
||||||
|
- name: lang_id
|
||||||
|
value: "0"
|
||||||
|
type: query
|
||||||
|
- name: country_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
4
bruno/folder.yml
Normal file
4
bruno/folder.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
info:
|
||||||
|
name: bruno
|
||||||
|
type: folder
|
||||||
|
seq: 18
|
||||||
2
go.mod
2
go.mod
@@ -5,6 +5,7 @@ go 1.26.0
|
|||||||
require (
|
require (
|
||||||
cloud.google.com/go/auth v0.16.4
|
cloud.google.com/go/auth v0.16.4
|
||||||
cloud.google.com/go/translate v1.12.7
|
cloud.google.com/go/translate v1.12.7
|
||||||
|
git.ma-al.com/goc_marek/gormcol v1.0.3
|
||||||
github.com/WinterYukky/gorm-extra-clause-plugin v0.4.0
|
github.com/WinterYukky/gorm-extra-clause-plugin v0.4.0
|
||||||
github.com/a-h/templ v0.3.1001
|
github.com/a-h/templ v0.3.1001
|
||||||
github.com/alecthomas/chroma v0.10.0
|
github.com/alecthomas/chroma v0.10.0
|
||||||
@@ -28,7 +29,6 @@ require (
|
|||||||
cloud.google.com/go v0.121.6 // indirect
|
cloud.google.com/go v0.121.6 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||||
git.ma-al.com/goc_marek/gormcol v1.0.3 // indirect
|
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
|||||||
11
go.sum
11
go.sum
@@ -217,17 +217,11 @@ go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2
|
|||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
|
||||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
|
||||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
|
||||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
|
||||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|
||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
|
||||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
@@ -244,17 +238,14 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
|
||||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
|
||||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||||
|
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
|
||||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
|
||||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||||
google.golang.org/api v0.247.0 h1:tSd/e0QrUlLsrwMKmkbQhYVa109qIintOls2Wh6bngc=
|
google.golang.org/api v0.247.0 h1:tSd/e0QrUlLsrwMKmkbQhYVa109qIintOls2Wh6bngc=
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ vue:
|
|||||||
- "**/dist/**"
|
- "**/dist/**"
|
||||||
- "**/.nuxt/**"
|
- "**/.nuxt/**"
|
||||||
- "**/.output/**"
|
- "**/.output/**"
|
||||||
|
tablename_prefix: "b2b_"
|
||||||
# Vue scope and components
|
# Vue scope and components
|
||||||
scope_id: 3
|
scope_id: 3
|
||||||
language_ids:
|
language_ids:
|
||||||
@@ -53,6 +54,7 @@ go:
|
|||||||
- "**/vendor/**"
|
- "**/vendor/**"
|
||||||
- "**/.git/**"
|
- "**/.git/**"
|
||||||
- "**/node_modules/**"
|
- "**/node_modules/**"
|
||||||
|
tablename_prefix: "b2b_"
|
||||||
# Go scope and components
|
# Go scope and components
|
||||||
scope_id: 1
|
scope_id: 1
|
||||||
scope_name: "Backend"
|
scope_name: "Backend"
|
||||||
@@ -73,6 +75,7 @@ go:
|
|||||||
# Legacy configuration (for backward compatibility)
|
# Legacy configuration (for backward compatibility)
|
||||||
# Used when vue/go sections are not present
|
# Used when vue/go sections are not present
|
||||||
save:
|
save:
|
||||||
|
tablename_prefix: "b2b_"
|
||||||
scope_id: 1
|
scope_id: 1
|
||||||
scope_name: "Default"
|
scope_name: "Default"
|
||||||
language_ids:
|
language_ids:
|
||||||
|
|||||||
Reference in New Issue
Block a user