feat: implemented delete application endpoint and dashboard action

This commit is contained in:
Tiago Yamamoto 2025-12-26 01:29:31 -03:00
parent 7b76b62490
commit 3fa875ed98
6 changed files with 74 additions and 6 deletions

View file

@ -477,7 +477,7 @@ func extractClientIP(r *http.Request) *string {
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {array} models.Notification
// @Success 200 {array} object
// @Failure 500 {string} string "Internal Server Error"
// @Router /api/v1/notifications [get]
func (h *CoreHandlers) ListNotifications(w http.ResponseWriter, r *http.Request) {
@ -566,7 +566,7 @@ func (h *CoreHandlers) MarkAllNotificationsAsRead(w http.ResponseWriter, r *http
// @Produce json
// @Security BearerAuth
// @Param ticket body object true "Ticket Details"
// @Success 201 {object} models.Ticket
// @Success 201 {object} object
// @Failure 400 {string} string "Invalid Request"
// @Failure 500 {string} string "Internal Server Error"
// @Router /api/v1/support/tickets [post]
@ -607,7 +607,7 @@ func (h *CoreHandlers) CreateTicket(w http.ResponseWriter, r *http.Request) {
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {array} models.Ticket
// @Success 200 {array} object
// @Failure 500 {string} string "Internal Server Error"
// @Router /api/v1/support/tickets [get]
func (h *CoreHandlers) ListTickets(w http.ResponseWriter, r *http.Request) {
@ -680,7 +680,7 @@ func (h *CoreHandlers) GetTicket(w http.ResponseWriter, r *http.Request) {
// @Security BearerAuth
// @Param id path string true "Ticket ID"
// @Param message body object true "Message"
// @Success 201 {object} models.TicketMessage
// @Success 201 {object} object
// @Failure 400 {string} string "Invalid Request"
// @Failure 500 {string} string "Internal Server Error"
// @Router /api/v1/support/tickets/{id}/messages [post]

View file

@ -139,3 +139,23 @@ func (h *ApplicationHandler) UpdateApplicationStatus(w http.ResponseWriter, r *h
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(app)
}
// DeleteApplication removes an application
// @Summary Delete Application
// @Description Remove an application by ID
// @Tags Applications
// @Accept json
// @Produce json
// @Param id path string true "Application ID"
// @Success 204 {object} nil
// @Failure 400 {string} string "Bad Request"
// @Failure 500 {string} string "Internal Server Error"
// @Router /api/v1/applications/{id} [delete]
func (h *ApplicationHandler) DeleteApplication(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if err := h.Service.DeleteApplication(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}

View file

@ -200,6 +200,7 @@ func NewRouter() http.Handler {
mux.HandleFunc("GET /api/v1/applications", applicationHandler.GetApplications)
mux.HandleFunc("GET /api/v1/applications/{id}", applicationHandler.GetApplicationByID)
mux.HandleFunc("PUT /api/v1/applications/{id}/status", applicationHandler.UpdateApplicationStatus)
mux.HandleFunc("DELETE /api/v1/applications/{id}", applicationHandler.DeleteApplication)
// --- STORAGE ROUTES ---
// Initialize S3 Storage (optional - graceful degradation if not configured)

View file

@ -141,3 +141,9 @@ func (s *ApplicationService) GetApplicationsByCompany(companyID string) ([]model
}
return apps, nil
}
func (s *ApplicationService) DeleteApplication(id string) error {
query := `DELETE FROM applications WHERE id = $1`
_, err := s.DB.Exec(query, id)
return err
}

View file

@ -33,7 +33,10 @@ import {
X,
Clock,
Star,
Trash,
} from "lucide-react"
import { applicationsApi } from "@/lib/api"
import { toast } from "sonner"
// Mock data - in production this would come from API
const mockApplications = [
@ -108,6 +111,21 @@ export default function ApplicationsPage() {
const [searchTerm, setSearchTerm] = useState("")
const [selectedApp, setSelectedApp] = useState<typeof mockApplications[0] | null>(null)
const handleDelete = async (id: string, e?: React.MouseEvent) => {
e?.stopPropagation()
if (!confirm("Are you sure you want to delete this application?")) return
try {
await applicationsApi.delete(id)
setApplications(applications.filter(a => a.id !== id))
toast.success("Application deleted")
if (selectedApp?.id === id) setSelectedApp(null)
} catch (error) {
console.error("Delete error:", error)
toast.error("Failed to delete application")
}
}
const filteredApplications = applications.filter((app) => {
const matchesStatus = statusFilter === "all" || app.status === statusFilter
const matchesSearch =
@ -265,6 +283,14 @@ export default function ApplicationsPage() {
<MessageSquare className="h-4 w-4 mr-2" />
Message
</Button>
<Button
variant="destructive"
size="sm"
className="flex-1 sm:flex-none"
onClick={(e) => handleDelete(app.id, e)}
>
<Trash className="h-4 w-4" />
</Button>
</div>
</div>
</CardContent>
@ -338,11 +364,19 @@ export default function ApplicationsPage() {
<MessageSquare className="h-4 w-4 mr-2" />
Contact
</Button>
<Button
className="flex-none"
variant="destructive"
onClick={() => handleDelete(selectedApp.id)}
>
<Trash className="h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
</div>
)}
</div>
)
}
</div >
)
}

View file

@ -307,6 +307,8 @@ export const adminCompaniesApi = {
}
};
// --- Jobs API (Public/Candidate) ---
export interface CreateJobPayload {
companyId: string;
@ -396,6 +398,11 @@ export const applicationsApi = {
if (params.companyId) query.append("companyId", params.companyId);
return apiRequest<any[]>(`/api/v1/applications?${query.toString()}`);
},
delete: (id: string) => {
return apiRequest<void>(`/api/v1/applications/${id}`, {
method: "DELETE"
})
},
};
// --- Helper Functions ---