feat: implemented delete application endpoint and dashboard action
This commit is contained in:
parent
7b76b62490
commit
3fa875ed98
6 changed files with 74 additions and 6 deletions
|
|
@ -477,7 +477,7 @@ func extractClientIP(r *http.Request) *string {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Success 200 {array} models.Notification
|
// @Success 200 {array} object
|
||||||
// @Failure 500 {string} string "Internal Server Error"
|
// @Failure 500 {string} string "Internal Server Error"
|
||||||
// @Router /api/v1/notifications [get]
|
// @Router /api/v1/notifications [get]
|
||||||
func (h *CoreHandlers) ListNotifications(w http.ResponseWriter, r *http.Request) {
|
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
|
// @Produce json
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Param ticket body object true "Ticket Details"
|
// @Param ticket body object true "Ticket Details"
|
||||||
// @Success 201 {object} models.Ticket
|
// @Success 201 {object} object
|
||||||
// @Failure 400 {string} string "Invalid Request"
|
// @Failure 400 {string} string "Invalid Request"
|
||||||
// @Failure 500 {string} string "Internal Server Error"
|
// @Failure 500 {string} string "Internal Server Error"
|
||||||
// @Router /api/v1/support/tickets [post]
|
// @Router /api/v1/support/tickets [post]
|
||||||
|
|
@ -607,7 +607,7 @@ func (h *CoreHandlers) CreateTicket(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Success 200 {array} models.Ticket
|
// @Success 200 {array} object
|
||||||
// @Failure 500 {string} string "Internal Server Error"
|
// @Failure 500 {string} string "Internal Server Error"
|
||||||
// @Router /api/v1/support/tickets [get]
|
// @Router /api/v1/support/tickets [get]
|
||||||
func (h *CoreHandlers) ListTickets(w http.ResponseWriter, r *http.Request) {
|
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
|
// @Security BearerAuth
|
||||||
// @Param id path string true "Ticket ID"
|
// @Param id path string true "Ticket ID"
|
||||||
// @Param message body object true "Message"
|
// @Param message body object true "Message"
|
||||||
// @Success 201 {object} models.TicketMessage
|
// @Success 201 {object} object
|
||||||
// @Failure 400 {string} string "Invalid Request"
|
// @Failure 400 {string} string "Invalid Request"
|
||||||
// @Failure 500 {string} string "Internal Server Error"
|
// @Failure 500 {string} string "Internal Server Error"
|
||||||
// @Router /api/v1/support/tickets/{id}/messages [post]
|
// @Router /api/v1/support/tickets/{id}/messages [post]
|
||||||
|
|
|
||||||
|
|
@ -139,3 +139,23 @@ func (h *ApplicationHandler) UpdateApplicationStatus(w http.ResponseWriter, r *h
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(app)
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,7 @@ func NewRouter() http.Handler {
|
||||||
mux.HandleFunc("GET /api/v1/applications", applicationHandler.GetApplications)
|
mux.HandleFunc("GET /api/v1/applications", applicationHandler.GetApplications)
|
||||||
mux.HandleFunc("GET /api/v1/applications/{id}", applicationHandler.GetApplicationByID)
|
mux.HandleFunc("GET /api/v1/applications/{id}", applicationHandler.GetApplicationByID)
|
||||||
mux.HandleFunc("PUT /api/v1/applications/{id}/status", applicationHandler.UpdateApplicationStatus)
|
mux.HandleFunc("PUT /api/v1/applications/{id}/status", applicationHandler.UpdateApplicationStatus)
|
||||||
|
mux.HandleFunc("DELETE /api/v1/applications/{id}", applicationHandler.DeleteApplication)
|
||||||
|
|
||||||
// --- STORAGE ROUTES ---
|
// --- STORAGE ROUTES ---
|
||||||
// Initialize S3 Storage (optional - graceful degradation if not configured)
|
// Initialize S3 Storage (optional - graceful degradation if not configured)
|
||||||
|
|
|
||||||
|
|
@ -141,3 +141,9 @@ func (s *ApplicationService) GetApplicationsByCompany(companyID string) ([]model
|
||||||
}
|
}
|
||||||
return apps, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@ import {
|
||||||
X,
|
X,
|
||||||
Clock,
|
Clock,
|
||||||
Star,
|
Star,
|
||||||
|
Trash,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
|
import { applicationsApi } from "@/lib/api"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
// Mock data - in production this would come from API
|
// Mock data - in production this would come from API
|
||||||
const mockApplications = [
|
const mockApplications = [
|
||||||
|
|
@ -108,6 +111,21 @@ export default function ApplicationsPage() {
|
||||||
const [searchTerm, setSearchTerm] = useState("")
|
const [searchTerm, setSearchTerm] = useState("")
|
||||||
const [selectedApp, setSelectedApp] = useState<typeof mockApplications[0] | null>(null)
|
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 filteredApplications = applications.filter((app) => {
|
||||||
const matchesStatus = statusFilter === "all" || app.status === statusFilter
|
const matchesStatus = statusFilter === "all" || app.status === statusFilter
|
||||||
const matchesSearch =
|
const matchesSearch =
|
||||||
|
|
@ -265,6 +283,14 @@ export default function ApplicationsPage() {
|
||||||
<MessageSquare className="h-4 w-4 mr-2" />
|
<MessageSquare className="h-4 w-4 mr-2" />
|
||||||
Message
|
Message
|
||||||
</Button>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
@ -338,11 +364,19 @@ export default function ApplicationsPage() {
|
||||||
<MessageSquare className="h-4 w-4 mr-2" />
|
<MessageSquare className="h-4 w-4 mr-2" />
|
||||||
Contact
|
Contact
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="flex-none"
|
||||||
|
variant="destructive"
|
||||||
|
onClick={() => handleDelete(selectedApp.id)}
|
||||||
|
>
|
||||||
|
<Trash className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)
|
||||||
</div>
|
}
|
||||||
|
</div >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,8 @@ export const adminCompaniesApi = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --- Jobs API (Public/Candidate) ---
|
// --- Jobs API (Public/Candidate) ---
|
||||||
export interface CreateJobPayload {
|
export interface CreateJobPayload {
|
||||||
companyId: string;
|
companyId: string;
|
||||||
|
|
@ -396,6 +398,11 @@ export const applicationsApi = {
|
||||||
if (params.companyId) query.append("companyId", params.companyId);
|
if (params.companyId) query.append("companyId", params.companyId);
|
||||||
return apiRequest<any[]>(`/api/v1/applications?${query.toString()}`);
|
return apiRequest<any[]>(`/api/v1/applications?${query.toString()}`);
|
||||||
},
|
},
|
||||||
|
delete: (id: string) => {
|
||||||
|
return apiRequest<void>(`/api/v1/applications/${id}`, {
|
||||||
|
method: "DELETE"
|
||||||
|
})
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Helper Functions ---
|
// --- Helper Functions ---
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue