diff --git a/internal/handler/auth.go b/internal/handler/auth.go index 42fa1a1..89c29f4 100644 --- a/internal/handler/auth.go +++ b/internal/handler/auth.go @@ -120,3 +120,77 @@ func generateToken() string { rand.Read(b) return hex.EncodeToString(b) } + +func (h *Handler) handleSignupPage(w http.ResponseWriter, r *http.Request) { + // If already logged in, redirect to dashboard + cookie, err := r.Cookie("session") + if err == nil && cookie.Value != "" { + var count int + h.db.QueryRow("SELECT COUNT(*) FROM sessions WHERE token = ? AND expires_at > datetime('now')", cookie.Value).Scan(&count) + if count > 0 { + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } + } + templates.Signup().Render(r.Context(), w) +} + +func (h *Handler) handleSignup(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Redirect(w, r, "/signup", http.StatusSeeOther) + return + } + + // Parse form + err := r.ParseForm() + if err != nil { + http.Redirect(w, r, "/signup", http.StatusSeeOther) + return + } + + orgName := r.FormValue("org_name") + name := r.FormValue("name") + email := r.FormValue("email") + password := r.FormValue("password") + + // Create organization + orgID := generateID() + _, err = h.db.Exec(`INSERT INTO organizations (id, name, slug) VALUES (?, ?, ?)`, orgID, orgName, orgName) + if err != nil { + http.Redirect(w, r, "/signup", http.StatusSeeOther) + return + } + + // Create user + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + userID := generateID() + _, err = h.db.Exec(`INSERT INTO profiles (id, email, full_name, role, organization_id, hashed_password) VALUES (?, ?, ?, ?, ?, ?)`, + userID, email, name, "owner", orgID, hashedPassword) + if err != nil { + http.Redirect(w, r, "/signup", http.StatusSeeOther) + return + } + + // Auto login + token := make([]byte, 32) + rand.Read(token) + tokenHex := hex.EncodeToString(token) + + _, err = h.db.Exec(`INSERT INTO sessions (id, user_id, token, expires_at) VALUES (?, ?, ?, datetime('now', '+24 hours'))`, + generateID(), userID, tokenHex) + if err != nil { + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + + http.SetCookie(w, &http.Cookie{ + Name: "session", + Value: tokenHex, + Path: "/", + Expires: time.Now().Add(24 * time.Hour), + HttpOnly: true, + }) + + http.Redirect(w, r, "/", http.StatusSeeOther) +} + diff --git a/internal/handler/handler.go b/internal/handler/handler.go index d313fb7..63da212 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -35,7 +35,9 @@ func (h *Handler) RegisterRoutes(mux *http.ServeMux) { // Auth mux.HandleFunc("/login", h.handleLoginPage) + mux.HandleFunc("/signup", h.handleSignupPage) mux.HandleFunc("/auth/login", h.handleLogin) + mux.HandleFunc("/auth/signup", h.handleSignup) mux.HandleFunc("/auth/logout", h.handleLogout) mux.HandleFunc("/auth/view-toggle", h.requireAuth(h.handleViewToggle)) diff --git a/templates/dealroom.templ b/templates/dealroom.templ index e4c87fc..0db7852 100644 --- a/templates/dealroom.templ +++ b/templates/dealroom.templ @@ -93,13 +93,27 @@ templ DealRoomDetail(profile *model.Profile, deal *model.Deal, folders []*model. } } + if profile.Role != "buyer" { +
+ +
+ }
- -
- + +
+ + if profile.Role != "buyer" { + + }
@@ -108,6 +122,7 @@ templ DealRoomDetail(profile *model.Profile, deal *model.Deal, folders []*model. + @@ -156,6 +171,7 @@ templ DealRoomDetail(profile *model.Profile, deal *model.Deal, folders []*model. + @@ -169,6 +185,13 @@ templ DealRoomDetail(profile *model.Profile, deal *model.Deal, folders []*model. +
Size Date StatusActions
Request Item Priority AtlasAtlas Notes Conf. Buyer Seller{ req.Description } @PriorityBadge(req.Priority) @StatusIcon(req.AtlasStatus) + if req.AtlasStatus == "Complete" { + Found in Q3 Financials.pdf + } else { + No notes + } + if req.Confidence > 0 { { fmt.Sprintf("%d%%", req.Confidence) } diff --git a/templates/login.templ b/templates/login.templ index 251cf3d..31ae858 100644 --- a/templates/login.templ +++ b/templates/login.templ @@ -55,6 +55,10 @@ templ Login() { Sign In +
+ Don't have an account? + Sign up your organization +
diff --git a/templates/signup.templ b/templates/signup.templ new file mode 100644 index 0000000..8e92dff --- /dev/null +++ b/templates/signup.templ @@ -0,0 +1,106 @@ +package templates + +templ Signup() { + + + + + + Dealspace AI - Organization Sign Up + + + + +
+
+ +
+
+ +
+ Dealspace AI +
+ +

Create an Organization

+

Set up your workspace to manage deals, invite your team, and collaborate with buyers securely.

+ + +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+
+ Already have an account? + Sign in +
+
+
+
+ + + + + +}