@@ -135,8 +135,8 @@ RegisterScreen::RegisterScreen(QWidget* parent) : QWidget(parent) {
135135 });
136136 connect (&auth, &auth::AuthManager::otp_verified, this , [this ]() {
137137 verify_btn_->setEnabled (true );
138- for (QLineEdit* w :
139- {first_name_, last_name_, email_, phone_, country_code_, password_, confirm_pw_, otp_input_}) {
138+ for (QLineEdit* w : {first_name_, last_name_, username_, email_, phone_, country_code_, password_,
139+ confirm_pw_, otp_input_}) {
140140 if (w)
141141 w->clear ();
142142 }
@@ -249,6 +249,10 @@ void RegisterScreen::build_form_page() {
249249 nrl->addLayout (ln_col);
250250 vl->addWidget (name_row);
251251
252+ // Username is required by POST /user/register; do not invent it from the
253+ // name fields (that hid the control and caused silent collisions — #318).
254+ add_field (username_lbl_, username_, vl);
255+
252256 add_field (email_lbl_, email_, vl);
253257
254258 // Phone + country code side by side
@@ -436,6 +440,8 @@ void RegisterScreen::retranslateUi() {
436440 first_name_lbl_->setText (tr (" FIRST NAME" ));
437441 if (last_name_lbl_)
438442 last_name_lbl_->setText (tr (" LAST NAME" ));
443+ if (username_lbl_)
444+ username_lbl_->setText (tr (" USERNAME" ));
439445 if (email_lbl_)
440446 email_lbl_->setText (tr (" EMAIL" ));
441447 if (code_lbl_)
@@ -451,6 +457,8 @@ void RegisterScreen::retranslateUi() {
451457 first_name_->setPlaceholderText (tr (" First" ));
452458 if (last_name_)
453459 last_name_->setPlaceholderText (tr (" Last" ));
460+ if (username_)
461+ username_->setPlaceholderText (tr (" 3-50 chars, letters/numbers/_" ));
454462 if (email_)
455463 email_->setPlaceholderText (tr (" user@domain.com" ));
456464 if (country_code_)
@@ -501,17 +509,30 @@ void RegisterScreen::on_register() {
501509
502510 QString fn = first_name_->text ().trimmed ();
503511 QString ln = last_name_->text ().trimmed ();
512+ QString username = auth::sanitize_input (username_->text ()).toLower ();
504513 QString em = email_->text ().trimmed ();
505514 QString ph = phone_->text ().trimmed ();
506515 QString cc = country_code_->text ().trimmed ();
507516 QString pw = password_->text ();
508517 QString cpw = confirm_pw_->text ();
509518
510- if (fn.isEmpty () || ln.isEmpty () || em.isEmpty () || ph.isEmpty () || pw.isEmpty () || cpw.isEmpty ()) {
519+ if (fn.isEmpty () || ln.isEmpty () || username.isEmpty () || em.isEmpty () || ph.isEmpty () || pw.isEmpty () ||
520+ cpw.isEmpty ()) {
511521 error_label_->setText (tr (" All fields are required" ));
512522 error_label_->show ();
513523 return ;
514524 }
525+ if (username.length () < 3 || username.length () > 50 ) {
526+ error_label_->setText (tr (" Username must be 3-50 characters" ));
527+ error_label_->show ();
528+ return ;
529+ }
530+ // Keep usernames URL/API-safe; spaces from names were a common failure mode.
531+ if (!QRegularExpression (QStringLiteral (" ^[a-z0-9_]+$" )).match (username).hasMatch ()) {
532+ error_label_->setText (tr (" Username may only contain letters, numbers, and underscores" ));
533+ error_label_->show ();
534+ return ;
535+ }
515536 if (cc.isEmpty ()) {
516537 error_label_->setText (tr (" Country code is required (e.g. +1, +91)" ));
517538 error_label_->show ();
@@ -539,13 +560,6 @@ void RegisterScreen::on_register() {
539560 return ;
540561 }
541562
542- QString username = auth::sanitize_input (fn + ln).toLower ();
543- if (username.length () < 3 || username.length () > 50 ) {
544- error_label_->setText (tr (" Username must be 3-50 characters" ));
545- error_label_->show ();
546- return ;
547- }
548-
549563 register_btn_->setEnabled (false );
550564 register_btn_->setText (tr (" CREATING... " ));
551565 auth::AuthManager::instance ().signup (username, em, pw, ph, {}, cc);
@@ -565,9 +579,7 @@ void RegisterScreen::on_verify_otp() {
565579}
566580
567581void RegisterScreen::on_resend_otp () {
568- QString fn = first_name_->text ().trimmed ();
569- QString ln = last_name_->text ().trimmed ();
570- QString username = auth::sanitize_input (fn + ln).toLower ();
582+ QString username = auth::sanitize_input (username_->text ()).toLower ();
571583 QString cc = country_code_->text ().trimmed ();
572584 if (!cc.isEmpty () && !cc.startsWith (' +' ))
573585 cc = ' +' + cc;
0 commit comments