1
0
forked from baron/baron-sso

feat: dynamic frontend tenant dropdown

This commit is contained in:
2026-04-06 16:56:33 +09:00
parent 46db7ac026
commit 332ac9c0d8
4 changed files with 83 additions and 51 deletions

View File

@@ -567,6 +567,7 @@ func main() {
// Signup Routes
signup := auth.Group("/signup")
signup.Get("/tenants", authHandler.GetActiveTenants)
signup.Post("/check-email", authHandler.CheckEmail)
signup.Post("/check-login-id", authHandler.CheckLoginID)
signup.Post("/send-email-code", authHandler.SendSignupEmailCode)

View File

@@ -463,6 +463,45 @@ func (h *AuthHandler) VerifySignupCode(c *fiber.Ctx) error {
}
// Signup - Finalize registration
func (h *AuthHandler) GetActiveTenants(c *fiber.Ctx) error {
if h.TenantService == nil {
return errorJSON(c, fiber.StatusServiceUnavailable, "Tenant service unavailable")
}
// List all tenants (we use a large limit for now to get all affiliates)
tenants, _, err := h.TenantService.ListTenants(c.Context(), 1000, 0, "")
if err != nil {
return errorJSON(c, fiber.StatusInternalServerError, "Failed to fetch tenants")
}
type tenantResp struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Type string `json:"type"`
Domains []string `json:"domains"`
}
var results []tenantResp
for _, t := range tenants {
if t.Status == domain.TenantStatusActive && (t.Type == domain.TenantTypeCompany || t.Type == domain.TenantTypeCompanyGroup) {
var domains []string
for _, d := range t.Domains {
domains = append(domains, d.Domain)
}
results = append(results, tenantResp{
ID: t.ID,
Name: t.Name,
Slug: t.Slug,
Type: t.Type,
Domains: domains,
})
}
}
return c.JSON(results)
}
func (h *AuthHandler) Signup(c *fiber.Ctx) error {
var req domain.SignupRequest
if err := c.BodyParser(&req); err != nil {

View File

@@ -923,6 +923,17 @@ class AuthProxyService {
}
}
static Future<List<Map<String, dynamic>>> getActiveTenants() async {
final url = Uri.parse('$_baseUrl/api/v1/auth/signup/tenants');
final response = await http.get(url);
if (response.statusCode == 200) {
final List<dynamic> data = jsonDecode(response.body);
return data.cast<Map<String, dynamic>>();
}
return [];
}
static Future<void> sendSignupCode(String target, String type) async {
final path = type == 'email' ? 'send-email-code' : 'send-sms-code';
final url = Uri.parse('$_baseUrl/api/v1/auth/signup/$path');

View File

@@ -54,6 +54,10 @@ class _SignupScreenState extends State<SignupScreen> {
bool _isPasswordObscured = true;
bool _isConfirmPasswordObscured = true;
// Dynamic Tenants
List<Map<String, dynamic>> _tenants = [];
final Map<String, String> _affiliateDomains = {};
// Inline Errors
String? _emailError;
String? _phoneError;
@@ -66,20 +70,32 @@ class _SignupScreenState extends State<SignupScreen> {
Timer? _phoneTimer;
int _phoneSeconds = 0;
// 가족사 도메인 맵
final Map<String, String> _affiliateDomains = {
'hanmaceng.co.kr': 'HANMAC',
'samaneng.com': 'SAMAN',
'jangheon.co.kr': 'JANGHEON',
'hallasanup.com': 'HALLA',
'pre-cast.co.kr': 'PTC',
'baroncs.co.kr': 'BARON',
};
@override
void initState() {
super.initState();
_loadPolicy();
_fetchTenants();
}
Future<void> _fetchTenants() async {
try {
final tenants = await AuthProxyService.getActiveTenants();
if (mounted) {
setState(() {
_tenants = tenants;
_affiliateDomains.clear();
for (var t in tenants) {
if (t['domains'] != null) {
for (var d in (t['domains'] as List)) {
_affiliateDomains[d.toString().toLowerCase()] = t['slug'];
}
}
}
});
}
} catch (e) {
debugPrint('Failed to load tenants: $e');
}
}
Future<void> _loadPolicy() async {
@@ -1505,47 +1521,12 @@ class _SignupScreenState extends State<SignupScreen> {
),
border: const OutlineInputBorder(),
),
items: [
DropdownMenuItem(
value: 'HANMAC',
child: Text(
tr('domain.company.hanmac'),
),
),
DropdownMenuItem(
value: 'SAMAN',
child: Text(
tr('domain.company.saman'),
),
),
DropdownMenuItem(
value: 'PTC',
child: Text(
tr(
'domain.company.ptc',
fallback: 'PTC',
),
),
),
DropdownMenuItem(
value: 'JANGHEON',
child: Text(
tr('domain.company.jangheon'),
),
),
DropdownMenuItem(
value: 'BARON',
child: Text(
tr('domain.company.baron'),
),
),
DropdownMenuItem(
value: 'HALLA',
child: Text(
tr('domain.company.halla'),
),
),
],
items: _tenants.map((t) {
return DropdownMenuItem<String>(
value: t['slug'],
child: Text(t['name'] ?? t['slug']),
);
}).toList(),
onChanged: _isAffiliateEmail
? null
: (val) => setState(