Add profile field breakdowns to analytics dashboard.
Expose user counts by education_level, occupation, learning_goal, and language_challange on GET /api/v1/analytics/dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f7d4b5c3fb
commit
e957eacf80
|
|
@ -68,6 +68,46 @@ WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.nar
|
||||||
GROUP BY u.knowledge_level
|
GROUP BY u.knowledge_level
|
||||||
ORDER BY count DESC;
|
ORDER BY count DESC;
|
||||||
|
|
||||||
|
-- name: AnalyticsUsersByEducationLevel :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')::text AS education_level,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
|
||||||
|
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')
|
||||||
|
ORDER BY count DESC;
|
||||||
|
|
||||||
|
-- name: AnalyticsUsersByOccupation :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')::text AS occupation,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
|
||||||
|
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')
|
||||||
|
ORDER BY count DESC;
|
||||||
|
|
||||||
|
-- name: AnalyticsUsersByLearningGoal :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')::text AS learning_goal,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
|
||||||
|
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')
|
||||||
|
ORDER BY count DESC;
|
||||||
|
|
||||||
|
-- name: AnalyticsUsersByLanguageChallange :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')::text AS language_challange,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
|
||||||
|
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')
|
||||||
|
ORDER BY count DESC;
|
||||||
|
|
||||||
-- name: AnalyticsUsersByRegion :many
|
-- name: AnalyticsUsersByRegion :many
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(u.region, 'unknown') AS region,
|
COALESCE(u.region, 'unknown') AS region,
|
||||||
|
|
|
||||||
|
|
@ -1080,6 +1080,47 @@ func (q *Queries) AnalyticsUsersByAgeGroup(ctx context.Context, arg AnalyticsUse
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AnalyticsUsersByEducationLevel = `-- name: AnalyticsUsersByEducationLevel :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')::text AS education_level,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE ($1::timestamptz IS NULL OR u.created_at >= $1::timestamptz)
|
||||||
|
AND ($2::timestamptz IS NULL OR u.created_at < $2::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')
|
||||||
|
ORDER BY count DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type AnalyticsUsersByEducationLevelParams struct {
|
||||||
|
RangeStart pgtype.Timestamptz `json:"range_start"`
|
||||||
|
RangeEnd pgtype.Timestamptz `json:"range_end"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnalyticsUsersByEducationLevelRow struct {
|
||||||
|
EducationLevel string `json:"education_level"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AnalyticsUsersByEducationLevel(ctx context.Context, arg AnalyticsUsersByEducationLevelParams) ([]AnalyticsUsersByEducationLevelRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, AnalyticsUsersByEducationLevel, arg.RangeStart, arg.RangeEnd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AnalyticsUsersByEducationLevelRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i AnalyticsUsersByEducationLevelRow
|
||||||
|
if err := rows.Scan(&i.EducationLevel, &i.Count); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const AnalyticsUsersByKnowledgeLevel = `-- name: AnalyticsUsersByKnowledgeLevel :many
|
const AnalyticsUsersByKnowledgeLevel = `-- name: AnalyticsUsersByKnowledgeLevel :many
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(u.knowledge_level, 'unknown') AS knowledge_level,
|
COALESCE(u.knowledge_level, 'unknown') AS knowledge_level,
|
||||||
|
|
@ -1121,6 +1162,129 @@ func (q *Queries) AnalyticsUsersByKnowledgeLevel(ctx context.Context, arg Analyt
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AnalyticsUsersByLanguageChallange = `-- name: AnalyticsUsersByLanguageChallange :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')::text AS language_challange,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE ($1::timestamptz IS NULL OR u.created_at >= $1::timestamptz)
|
||||||
|
AND ($2::timestamptz IS NULL OR u.created_at < $2::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')
|
||||||
|
ORDER BY count DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type AnalyticsUsersByLanguageChallangeParams struct {
|
||||||
|
RangeStart pgtype.Timestamptz `json:"range_start"`
|
||||||
|
RangeEnd pgtype.Timestamptz `json:"range_end"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnalyticsUsersByLanguageChallangeRow struct {
|
||||||
|
LanguageChallange string `json:"language_challange"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AnalyticsUsersByLanguageChallange(ctx context.Context, arg AnalyticsUsersByLanguageChallangeParams) ([]AnalyticsUsersByLanguageChallangeRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, AnalyticsUsersByLanguageChallange, arg.RangeStart, arg.RangeEnd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AnalyticsUsersByLanguageChallangeRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i AnalyticsUsersByLanguageChallangeRow
|
||||||
|
if err := rows.Scan(&i.LanguageChallange, &i.Count); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnalyticsUsersByLearningGoal = `-- name: AnalyticsUsersByLearningGoal :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')::text AS learning_goal,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE ($1::timestamptz IS NULL OR u.created_at >= $1::timestamptz)
|
||||||
|
AND ($2::timestamptz IS NULL OR u.created_at < $2::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')
|
||||||
|
ORDER BY count DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type AnalyticsUsersByLearningGoalParams struct {
|
||||||
|
RangeStart pgtype.Timestamptz `json:"range_start"`
|
||||||
|
RangeEnd pgtype.Timestamptz `json:"range_end"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnalyticsUsersByLearningGoalRow struct {
|
||||||
|
LearningGoal string `json:"learning_goal"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AnalyticsUsersByLearningGoal(ctx context.Context, arg AnalyticsUsersByLearningGoalParams) ([]AnalyticsUsersByLearningGoalRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, AnalyticsUsersByLearningGoal, arg.RangeStart, arg.RangeEnd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AnalyticsUsersByLearningGoalRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i AnalyticsUsersByLearningGoalRow
|
||||||
|
if err := rows.Scan(&i.LearningGoal, &i.Count); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnalyticsUsersByOccupation = `-- name: AnalyticsUsersByOccupation :many
|
||||||
|
SELECT
|
||||||
|
COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')::text AS occupation,
|
||||||
|
COUNT(*)::bigint AS count
|
||||||
|
FROM users u
|
||||||
|
WHERE ($1::timestamptz IS NULL OR u.created_at >= $1::timestamptz)
|
||||||
|
AND ($2::timestamptz IS NULL OR u.created_at < $2::timestamptz)
|
||||||
|
GROUP BY COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')
|
||||||
|
ORDER BY count DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type AnalyticsUsersByOccupationParams struct {
|
||||||
|
RangeStart pgtype.Timestamptz `json:"range_start"`
|
||||||
|
RangeEnd pgtype.Timestamptz `json:"range_end"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnalyticsUsersByOccupationRow struct {
|
||||||
|
Occupation string `json:"occupation"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AnalyticsUsersByOccupation(ctx context.Context, arg AnalyticsUsersByOccupationParams) ([]AnalyticsUsersByOccupationRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, AnalyticsUsersByOccupation, arg.RangeStart, arg.RangeEnd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AnalyticsUsersByOccupationRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i AnalyticsUsersByOccupationRow
|
||||||
|
if err := rows.Scan(&i.Occupation, &i.Count); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const AnalyticsUsersByRegion = `-- name: AnalyticsUsersByRegion :many
|
const AnalyticsUsersByRegion = `-- name: AnalyticsUsersByRegion :many
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(u.region, 'unknown') AS region,
|
COALESCE(u.region, 'unknown') AS region,
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,17 @@ type Faq struct {
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FieldOption struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
FieldKey string `json:"field_key"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type GlobalSetting struct {
|
type GlobalSetting struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ type AnalyticsUsersSection struct {
|
||||||
ByRole []AnalyticsLabelCount `json:"by_role"`
|
ByRole []AnalyticsLabelCount `json:"by_role"`
|
||||||
ByStatus []AnalyticsLabelCount `json:"by_status"`
|
ByStatus []AnalyticsLabelCount `json:"by_status"`
|
||||||
ByAgeGroup []AnalyticsLabelCount `json:"by_age_group"`
|
ByAgeGroup []AnalyticsLabelCount `json:"by_age_group"`
|
||||||
|
ByEducationLevel []AnalyticsLabelCount `json:"by_education_level"`
|
||||||
|
ByOccupation []AnalyticsLabelCount `json:"by_occupation"`
|
||||||
|
ByLearningGoal []AnalyticsLabelCount `json:"by_learning_goal"`
|
||||||
|
ByLanguageChallange []AnalyticsLabelCount `json:"by_language_challange"`
|
||||||
ByKnowledgeLevel []AnalyticsLabelCount `json:"by_knowledge_level"`
|
ByKnowledgeLevel []AnalyticsLabelCount `json:"by_knowledge_level"`
|
||||||
ByRegion []AnalyticsLabelCount `json:"by_region"`
|
ByRegion []AnalyticsLabelCount `json:"by_region"`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,22 @@ func (h *Handler) GetAnalyticsDashboard(c *fiber.Ctx) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by age group")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by age group")
|
||||||
}
|
}
|
||||||
|
usersByEducation, err := h.analyticsDB.AnalyticsUsersByEducationLevel(ctx, p.UsersByEducationLevel)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by education level")
|
||||||
|
}
|
||||||
|
usersByOccupation, err := h.analyticsDB.AnalyticsUsersByOccupation(ctx, p.UsersByOccupation)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by occupation")
|
||||||
|
}
|
||||||
|
usersByLearningGoal, err := h.analyticsDB.AnalyticsUsersByLearningGoal(ctx, p.UsersByLearningGoal)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by learning goal")
|
||||||
|
}
|
||||||
|
usersByLanguageChallange, err := h.analyticsDB.AnalyticsUsersByLanguageChallange(ctx, p.UsersByLanguageChallange)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by language challenge")
|
||||||
|
}
|
||||||
usersByKnowledge, err := h.analyticsDB.AnalyticsUsersByKnowledgeLevel(ctx, p.UsersByKnowledgeLevel)
|
usersByKnowledge, err := h.analyticsDB.AnalyticsUsersByKnowledgeLevel(ctx, p.UsersByKnowledgeLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by knowledge level")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by knowledge level")
|
||||||
|
|
@ -179,7 +195,11 @@ func (h *Handler) GetAnalyticsDashboard(c *fiber.Ctx) error {
|
||||||
dashboard := domain.AnalyticsDashboard{
|
dashboard := domain.AnalyticsDashboard{
|
||||||
GeneratedAt: time.Now().UTC(),
|
GeneratedAt: time.Now().UTC(),
|
||||||
DateFilter: filter,
|
DateFilter: filter,
|
||||||
Users: mapUsersSection(usersSummary, usersByRole, usersByStatus, usersByAge, usersByKnowledge, usersByRegion, userRegs),
|
Users: mapUsersSection(
|
||||||
|
usersSummary, usersByRole, usersByStatus, usersByAge,
|
||||||
|
usersByEducation, usersByOccupation, usersByLearningGoal, usersByLanguageChallange,
|
||||||
|
usersByKnowledge, usersByRegion, userRegs,
|
||||||
|
),
|
||||||
Subscriptions: mapSubscriptionsSection(subsSummary, subsByStatus, revenueByPlan, newSubs30),
|
Subscriptions: mapSubscriptionsSection(subsSummary, subsByStatus, revenueByPlan, newSubs30),
|
||||||
Payments: mapPaymentsSection(paymentsSummary, paymentsByStatus, paymentsByMethod, revenue30, revenueMonthlyRows, monthlyRevenueYear),
|
Payments: mapPaymentsSection(paymentsSummary, paymentsByStatus, paymentsByMethod, revenue30, revenueMonthlyRows, monthlyRevenueYear),
|
||||||
Courses: mapCoursesSection(courseCounts),
|
Courses: mapCoursesSection(courseCounts),
|
||||||
|
|
@ -225,6 +245,10 @@ func mapUsersSection(
|
||||||
byRole []dbgen.AnalyticsUsersByRoleRow,
|
byRole []dbgen.AnalyticsUsersByRoleRow,
|
||||||
byStatus []dbgen.AnalyticsUsersByStatusRow,
|
byStatus []dbgen.AnalyticsUsersByStatusRow,
|
||||||
byAge []dbgen.AnalyticsUsersByAgeGroupRow,
|
byAge []dbgen.AnalyticsUsersByAgeGroupRow,
|
||||||
|
byEducation []dbgen.AnalyticsUsersByEducationLevelRow,
|
||||||
|
byOccupation []dbgen.AnalyticsUsersByOccupationRow,
|
||||||
|
byLearningGoal []dbgen.AnalyticsUsersByLearningGoalRow,
|
||||||
|
byLanguageChallange []dbgen.AnalyticsUsersByLanguageChallangeRow,
|
||||||
byKnowledge []dbgen.AnalyticsUsersByKnowledgeLevelRow,
|
byKnowledge []dbgen.AnalyticsUsersByKnowledgeLevelRow,
|
||||||
byRegion []dbgen.AnalyticsUsersByRegionRow,
|
byRegion []dbgen.AnalyticsUsersByRegionRow,
|
||||||
regs []dbgen.AnalyticsUserRegistrationsLast30DaysRow,
|
regs []dbgen.AnalyticsUserRegistrationsLast30DaysRow,
|
||||||
|
|
@ -241,6 +265,22 @@ func mapUsersSection(
|
||||||
for i, r := range byAge {
|
for i, r := range byAge {
|
||||||
ages[i] = domain.AnalyticsLabelCount{Label: r.AgeGroup, Count: r.Count}
|
ages[i] = domain.AnalyticsLabelCount{Label: r.AgeGroup, Count: r.Count}
|
||||||
}
|
}
|
||||||
|
education := make([]domain.AnalyticsLabelCount, len(byEducation))
|
||||||
|
for i, r := range byEducation {
|
||||||
|
education[i] = domain.AnalyticsLabelCount{Label: r.EducationLevel, Count: r.Count}
|
||||||
|
}
|
||||||
|
occupations := make([]domain.AnalyticsLabelCount, len(byOccupation))
|
||||||
|
for i, r := range byOccupation {
|
||||||
|
occupations[i] = domain.AnalyticsLabelCount{Label: r.Occupation, Count: r.Count}
|
||||||
|
}
|
||||||
|
learningGoals := make([]domain.AnalyticsLabelCount, len(byLearningGoal))
|
||||||
|
for i, r := range byLearningGoal {
|
||||||
|
learningGoals[i] = domain.AnalyticsLabelCount{Label: r.LearningGoal, Count: r.Count}
|
||||||
|
}
|
||||||
|
languageChallanges := make([]domain.AnalyticsLabelCount, len(byLanguageChallange))
|
||||||
|
for i, r := range byLanguageChallange {
|
||||||
|
languageChallanges[i] = domain.AnalyticsLabelCount{Label: r.LanguageChallange, Count: r.Count}
|
||||||
|
}
|
||||||
knowledge := make([]domain.AnalyticsLabelCount, len(byKnowledge))
|
knowledge := make([]domain.AnalyticsLabelCount, len(byKnowledge))
|
||||||
for i, r := range byKnowledge {
|
for i, r := range byKnowledge {
|
||||||
knowledge[i] = domain.AnalyticsLabelCount{Label: r.KnowledgeLevel, Count: r.Count}
|
knowledge[i] = domain.AnalyticsLabelCount{Label: r.KnowledgeLevel, Count: r.Count}
|
||||||
|
|
@ -261,6 +301,10 @@ func mapUsersSection(
|
||||||
ByRole: roles,
|
ByRole: roles,
|
||||||
ByStatus: statuses,
|
ByStatus: statuses,
|
||||||
ByAgeGroup: ages,
|
ByAgeGroup: ages,
|
||||||
|
ByEducationLevel: education,
|
||||||
|
ByOccupation: occupations,
|
||||||
|
ByLearningGoal: learningGoals,
|
||||||
|
ByLanguageChallange: languageChallanges,
|
||||||
ByKnowledgeLevel: knowledge,
|
ByKnowledgeLevel: knowledge,
|
||||||
ByRegion: regions,
|
ByRegion: regions,
|
||||||
RegistrationsLast30Days: timePoints,
|
RegistrationsLast30Days: timePoints,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ type analyticsQueryParams struct {
|
||||||
UsersByRole dbgen.AnalyticsUsersByRoleParams
|
UsersByRole dbgen.AnalyticsUsersByRoleParams
|
||||||
UsersByStatus dbgen.AnalyticsUsersByStatusParams
|
UsersByStatus dbgen.AnalyticsUsersByStatusParams
|
||||||
UsersByAgeGroup dbgen.AnalyticsUsersByAgeGroupParams
|
UsersByAgeGroup dbgen.AnalyticsUsersByAgeGroupParams
|
||||||
|
UsersByEducationLevel dbgen.AnalyticsUsersByEducationLevelParams
|
||||||
|
UsersByOccupation dbgen.AnalyticsUsersByOccupationParams
|
||||||
|
UsersByLearningGoal dbgen.AnalyticsUsersByLearningGoalParams
|
||||||
|
UsersByLanguageChallange dbgen.AnalyticsUsersByLanguageChallangeParams
|
||||||
UsersByKnowledgeLevel dbgen.AnalyticsUsersByKnowledgeLevelParams
|
UsersByKnowledgeLevel dbgen.AnalyticsUsersByKnowledgeLevelParams
|
||||||
UsersByRegion dbgen.AnalyticsUsersByRegionParams
|
UsersByRegion dbgen.AnalyticsUsersByRegionParams
|
||||||
UserRegistrationsSeries dbgen.AnalyticsUserRegistrationsLast30DaysParams
|
UserRegistrationsSeries dbgen.AnalyticsUserRegistrationsLast30DaysParams
|
||||||
|
|
@ -59,6 +63,10 @@ func newAnalyticsQueryParams(f domain.AnalyticsDateFilter) analyticsQueryParams
|
||||||
UsersByRole: dbgen.AnalyticsUsersByRoleParams{RangeStart: rs, RangeEnd: re},
|
UsersByRole: dbgen.AnalyticsUsersByRoleParams{RangeStart: rs, RangeEnd: re},
|
||||||
UsersByStatus: dbgen.AnalyticsUsersByStatusParams{RangeStart: rs, RangeEnd: re},
|
UsersByStatus: dbgen.AnalyticsUsersByStatusParams{RangeStart: rs, RangeEnd: re},
|
||||||
UsersByAgeGroup: dbgen.AnalyticsUsersByAgeGroupParams{RangeStart: rs, RangeEnd: re},
|
UsersByAgeGroup: dbgen.AnalyticsUsersByAgeGroupParams{RangeStart: rs, RangeEnd: re},
|
||||||
|
UsersByEducationLevel: dbgen.AnalyticsUsersByEducationLevelParams{RangeStart: rs, RangeEnd: re},
|
||||||
|
UsersByOccupation: dbgen.AnalyticsUsersByOccupationParams{RangeStart: rs, RangeEnd: re},
|
||||||
|
UsersByLearningGoal: dbgen.AnalyticsUsersByLearningGoalParams{RangeStart: rs, RangeEnd: re},
|
||||||
|
UsersByLanguageChallange: dbgen.AnalyticsUsersByLanguageChallangeParams{RangeStart: rs, RangeEnd: re},
|
||||||
UsersByKnowledgeLevel: dbgen.AnalyticsUsersByKnowledgeLevelParams{RangeStart: rs, RangeEnd: re},
|
UsersByKnowledgeLevel: dbgen.AnalyticsUsersByKnowledgeLevelParams{RangeStart: rs, RangeEnd: re},
|
||||||
UsersByRegion: dbgen.AnalyticsUsersByRegionParams{RangeStart: rs, RangeEnd: re},
|
UsersByRegion: dbgen.AnalyticsUsersByRegionParams{RangeStart: rs, RangeEnd: re},
|
||||||
UserRegistrationsSeries: series,
|
UserRegistrationsSeries: series,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user