mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 15:20:13 +01:00
Add inline context creation when creating todos
Users can now create a new context directly from the todo creation modal without having to navigate away to the contexts page. Changes: - Added "Create new context..." option to context dropdown in todo modal - Added inline form that appears when user selects "Create new context" - Added JavaScript to show/hide the new context input field dynamically - Added form validation to ensure either an existing context is selected or a new context name is provided - Updated HandleCreateTodo to detect when user wants to create a new context (context_id == "__new__") and create it before creating the todo - New contexts are created with proper position ordering UX Flow: 1. User clicks "New Todo" 2. User selects "Create new context..." from dropdown 3. Input field appears below for entering context name 4. User enters context name (e.g., "@home", "@work") 5. When form is submitted, context is created first, then todo is created with the new context automatically assigned 6. User is redirected back to todos page with both new context and todo visible This streamlines the workflow and eliminates context switching when users need to quickly add a todo with a new context.
This commit is contained in:
parent
51c4b6d3c3
commit
d2a9c79633
2 changed files with 99 additions and 20 deletions
|
|
@ -182,15 +182,19 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="context_id">Context *</label>
|
||||
<select id="context_id" name="context_id" required>
|
||||
<option value="">Select a context...</option>
|
||||
<select id="context_id" name="context_id" onchange="handleContextChange()">
|
||||
<option value="">Select existing context...</option>
|
||||
{{range .Contexts}}
|
||||
<option value="{{.ID}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
<option value="__new__">➕ Create new context...</option>
|
||||
</select>
|
||||
{{if not .Contexts}}
|
||||
<small style="color: var(--text-secondary);">You need to create a context first before creating todos.</small>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="new_context_group" style="display: none;">
|
||||
<label for="new_context_name">New Context Name</label>
|
||||
<input type="text" id="new_context_name" name="new_context_name" placeholder="e.g., @home, @work, @errands">
|
||||
<small style="color: var(--text-secondary);">Enter a name and it will be created when you save the todo.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
|
@ -214,12 +218,54 @@
|
|||
<script>
|
||||
function openNewTodoModal() {
|
||||
document.getElementById('newTodoModal').classList.add('active');
|
||||
// Reset the form
|
||||
document.getElementById('context_id').value = '';
|
||||
document.getElementById('new_context_group').style.display = 'none';
|
||||
document.getElementById('new_context_name').value = '';
|
||||
}
|
||||
|
||||
function closeNewTodoModal() {
|
||||
document.getElementById('newTodoModal').classList.remove('active');
|
||||
}
|
||||
|
||||
function handleContextChange() {
|
||||
const contextSelect = document.getElementById('context_id');
|
||||
const newContextGroup = document.getElementById('new_context_group');
|
||||
const newContextInput = document.getElementById('new_context_name');
|
||||
|
||||
if (contextSelect.value === '__new__') {
|
||||
// Show the new context input field
|
||||
newContextGroup.style.display = 'block';
|
||||
newContextInput.required = true;
|
||||
newContextInput.focus();
|
||||
} else {
|
||||
// Hide the new context input field
|
||||
newContextGroup.style.display = 'none';
|
||||
newContextInput.required = false;
|
||||
newContextInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Form validation before submission
|
||||
document.querySelector('#newTodoModal form').addEventListener('submit', function(e) {
|
||||
const contextSelect = document.getElementById('context_id');
|
||||
const newContextName = document.getElementById('new_context_name');
|
||||
|
||||
if (contextSelect.value === '__new__') {
|
||||
if (!newContextName.value.trim()) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a name for the new context');
|
||||
newContextName.focus();
|
||||
return false;
|
||||
}
|
||||
} else if (!contextSelect.value) {
|
||||
e.preventDefault();
|
||||
alert('Please select a context or create a new one');
|
||||
contextSelect.focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('newTodoModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
|
|
|
|||
|
|
@ -327,25 +327,58 @@ func (h *WebHandler) HandleCreateTodo(c *gin.Context) {
|
|||
|
||||
notes := c.PostForm("notes")
|
||||
contextIDStr := c.PostForm("context_id")
|
||||
newContextName := c.PostForm("new_context_name")
|
||||
dueDateStr := c.PostForm("due_date")
|
||||
|
||||
// Parse context ID (required)
|
||||
if contextIDStr == "" {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Context is required")
|
||||
return
|
||||
}
|
||||
|
||||
var contextID uint
|
||||
if _, err := fmt.Sscanf(contextIDStr, "%d", &contextID); err != nil {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Invalid context")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify context exists and belongs to user
|
||||
var context models.Context
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", contextID, user.ID).First(&context).Error; err != nil {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Context not found")
|
||||
return
|
||||
// Check if user wants to create a new context
|
||||
if contextIDStr == "__new__" {
|
||||
// Validate new context name
|
||||
if newContextName == "" {
|
||||
c.Redirect(http.StatusFound, "/todos?error=New context name is required")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the highest position value for proper ordering
|
||||
var maxPosition int
|
||||
database.DB.Model(&models.Context{}).
|
||||
Where("user_id = ?", user.ID).
|
||||
Select("COALESCE(MAX(position), 0)").
|
||||
Scan(&maxPosition)
|
||||
|
||||
// Create new context
|
||||
newContext := models.Context{
|
||||
UserID: user.ID,
|
||||
Name: newContextName,
|
||||
State: "active",
|
||||
Position: maxPosition + 1,
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&newContext).Error; err != nil {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Failed to create context: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
contextID = newContext.ID
|
||||
} else {
|
||||
// Parse existing context ID (required)
|
||||
if contextIDStr == "" {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Context is required")
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := fmt.Sscanf(contextIDStr, "%d", &contextID); err != nil {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Invalid context")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify context exists and belongs to user
|
||||
var context models.Context
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", contextID, user.ID).First(&context).Error; err != nil {
|
||||
c.Redirect(http.StatusFound, "/todos?error=Context not found")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create todo
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue