refactor: redesign planos interface with design system patterns
- Create CreatePlanModal component with Headless UI Dialog - Implement dark mode support throughout plans UI - Update plans/page.tsx with professional card layout - Update plans/[id]/page.tsx with consistent styling - Add proper spacing, typography, and color consistency - Implement smooth animations and transitions - Add success/error message feedback - Improve form UX with better input styling
This commit is contained in:
283
backend/internal/repository/plan_repository.go
Normal file
283
backend/internal/repository/plan_repository.go
Normal file
@@ -0,0 +1,283 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"aggios-app/backend/internal/domain"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
// PlanRepository handles database operations for plans
|
||||
type PlanRepository struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewPlanRepository creates a new plan repository
|
||||
func NewPlanRepository(db *sql.DB) *PlanRepository {
|
||||
return &PlanRepository{db: db}
|
||||
}
|
||||
|
||||
// Create creates a new plan
|
||||
func (r *PlanRepository) Create(plan *domain.Plan) error {
|
||||
query := `
|
||||
INSERT INTO plans (id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
|
||||
RETURNING id, created_at, updated_at
|
||||
`
|
||||
|
||||
now := time.Now()
|
||||
plan.ID = uuid.New()
|
||||
plan.CreatedAt = now
|
||||
plan.UpdatedAt = now
|
||||
|
||||
features := pq.Array(plan.Features)
|
||||
differentiators := pq.Array(plan.Differentiators)
|
||||
|
||||
return r.db.QueryRow(
|
||||
query,
|
||||
plan.ID,
|
||||
plan.Name,
|
||||
plan.Slug,
|
||||
plan.Description,
|
||||
plan.MinUsers,
|
||||
plan.MaxUsers,
|
||||
plan.MonthlyPrice,
|
||||
plan.AnnualPrice,
|
||||
features,
|
||||
differentiators,
|
||||
plan.StorageGB,
|
||||
plan.IsActive,
|
||||
plan.CreatedAt,
|
||||
plan.UpdatedAt,
|
||||
).Scan(&plan.ID, &plan.CreatedAt, &plan.UpdatedAt)
|
||||
}
|
||||
|
||||
// GetByID retrieves a plan by ID
|
||||
func (r *PlanRepository) GetByID(id uuid.UUID) (*domain.Plan, error) {
|
||||
query := `
|
||||
SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
|
||||
FROM plans
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
plan := &domain.Plan{}
|
||||
var features, differentiators pq.StringArray
|
||||
|
||||
err := r.db.QueryRow(query, id).Scan(
|
||||
&plan.ID,
|
||||
&plan.Name,
|
||||
&plan.Slug,
|
||||
&plan.Description,
|
||||
&plan.MinUsers,
|
||||
&plan.MaxUsers,
|
||||
&plan.MonthlyPrice,
|
||||
&plan.AnnualPrice,
|
||||
&features,
|
||||
&differentiators,
|
||||
&plan.StorageGB,
|
||||
&plan.IsActive,
|
||||
&plan.CreatedAt,
|
||||
&plan.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plan.Features = []string(features)
|
||||
plan.Differentiators = []string(differentiators)
|
||||
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
// GetBySlug retrieves a plan by slug
|
||||
func (r *PlanRepository) GetBySlug(slug string) (*domain.Plan, error) {
|
||||
query := `
|
||||
SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
|
||||
FROM plans
|
||||
WHERE slug = $1
|
||||
`
|
||||
|
||||
plan := &domain.Plan{}
|
||||
var features, differentiators pq.StringArray
|
||||
|
||||
err := r.db.QueryRow(query, slug).Scan(
|
||||
&plan.ID,
|
||||
&plan.Name,
|
||||
&plan.Slug,
|
||||
&plan.Description,
|
||||
&plan.MinUsers,
|
||||
&plan.MaxUsers,
|
||||
&plan.MonthlyPrice,
|
||||
&plan.AnnualPrice,
|
||||
&features,
|
||||
&differentiators,
|
||||
&plan.StorageGB,
|
||||
&plan.IsActive,
|
||||
&plan.CreatedAt,
|
||||
&plan.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plan.Features = []string(features)
|
||||
plan.Differentiators = []string(differentiators)
|
||||
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
// ListAll retrieves all plans
|
||||
func (r *PlanRepository) ListAll() ([]*domain.Plan, error) {
|
||||
query := `
|
||||
SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
|
||||
FROM plans
|
||||
ORDER BY min_users ASC
|
||||
`
|
||||
|
||||
rows, err := r.db.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var plans []*domain.Plan
|
||||
|
||||
for rows.Next() {
|
||||
plan := &domain.Plan{}
|
||||
var features, differentiators pq.StringArray
|
||||
|
||||
err := rows.Scan(
|
||||
&plan.ID,
|
||||
&plan.Name,
|
||||
&plan.Slug,
|
||||
&plan.Description,
|
||||
&plan.MinUsers,
|
||||
&plan.MaxUsers,
|
||||
&plan.MonthlyPrice,
|
||||
&plan.AnnualPrice,
|
||||
&features,
|
||||
&differentiators,
|
||||
&plan.StorageGB,
|
||||
&plan.IsActive,
|
||||
&plan.CreatedAt,
|
||||
&plan.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plan.Features = []string(features)
|
||||
plan.Differentiators = []string(differentiators)
|
||||
plans = append(plans, plan)
|
||||
}
|
||||
|
||||
return plans, rows.Err()
|
||||
}
|
||||
|
||||
// ListActive retrieves all active plans
|
||||
func (r *PlanRepository) ListActive() ([]*domain.Plan, error) {
|
||||
query := `
|
||||
SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
|
||||
FROM plans
|
||||
WHERE is_active = true
|
||||
ORDER BY min_users ASC
|
||||
`
|
||||
|
||||
rows, err := r.db.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var plans []*domain.Plan
|
||||
|
||||
for rows.Next() {
|
||||
plan := &domain.Plan{}
|
||||
var features, differentiators pq.StringArray
|
||||
|
||||
err := rows.Scan(
|
||||
&plan.ID,
|
||||
&plan.Name,
|
||||
&plan.Slug,
|
||||
&plan.Description,
|
||||
&plan.MinUsers,
|
||||
&plan.MaxUsers,
|
||||
&plan.MonthlyPrice,
|
||||
&plan.AnnualPrice,
|
||||
&features,
|
||||
&differentiators,
|
||||
&plan.StorageGB,
|
||||
&plan.IsActive,
|
||||
&plan.CreatedAt,
|
||||
&plan.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plan.Features = []string(features)
|
||||
plan.Differentiators = []string(differentiators)
|
||||
plans = append(plans, plan)
|
||||
}
|
||||
|
||||
return plans, rows.Err()
|
||||
}
|
||||
|
||||
// Update updates a plan
|
||||
func (r *PlanRepository) Update(plan *domain.Plan) error {
|
||||
query := `
|
||||
UPDATE plans
|
||||
SET name = $2, slug = $3, description = $4, min_users = $5, max_users = $6, monthly_price = $7, annual_price = $8, features = $9, differentiators = $10, storage_gb = $11, is_active = $12, updated_at = $13
|
||||
WHERE id = $1
|
||||
RETURNING updated_at
|
||||
`
|
||||
|
||||
plan.UpdatedAt = time.Now()
|
||||
|
||||
features := pq.Array(plan.Features)
|
||||
differentiators := pq.Array(plan.Differentiators)
|
||||
|
||||
return r.db.QueryRow(
|
||||
query,
|
||||
plan.ID,
|
||||
plan.Name,
|
||||
plan.Slug,
|
||||
plan.Description,
|
||||
plan.MinUsers,
|
||||
plan.MaxUsers,
|
||||
plan.MonthlyPrice,
|
||||
plan.AnnualPrice,
|
||||
features,
|
||||
differentiators,
|
||||
plan.StorageGB,
|
||||
plan.IsActive,
|
||||
plan.UpdatedAt,
|
||||
).Scan(&plan.UpdatedAt)
|
||||
}
|
||||
|
||||
// Delete deletes a plan
|
||||
func (r *PlanRepository) Delete(id uuid.UUID) error {
|
||||
query := `DELETE FROM plans WHERE id = $1`
|
||||
result, err := r.db.Exec(query, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user