Skip to content

Commit

Permalink
Dynamically render search results for CodeSystem by OID (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
katyasoup authored Sep 25, 2024
1 parent 02761e5 commit 724fe91
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 109 deletions.
59 changes: 57 additions & 2 deletions internal/app/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,63 @@ func (app *Application) home(w http.ResponseWriter, r *http.Request) {
component.Render(r.Context(), w)
}

func (app *Application) searchResults(w http.ResponseWriter, r *http.Request) {
component := components.SearchResults("Search", "Hepatitis")
func (app *Application) formSearch(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
searchTerm := r.Form["search"][0]
searchType := r.Form["options"][0]
app.search(w, r, searchTerm, searchType)
}

func (app *Application) directSearch(w http.ResponseWriter, r *http.Request) {
searchType := r.URL.Query().Get("type")
searchTerm := r.URL.Query().Get("input")
app.search(w, r, searchTerm, searchType)
}

func (app *Application) search(w http.ResponseWriter, r *http.Request, searchTerm, searchType string) {
rp := app.repository
logger := app.logger

var result = &models.CodeSystemResultRow{}
defaultPageCount := 5

// retrieve code system
codeSystem, err := rp.GetCodeSystemsByLikeOID(r.Context(), searchTerm)
if err != nil || len(*codeSystem) < 1 {
if err == nil {
err = sql.ErrNoRows
}
customErrors.SearchError(w, r, err, searchTerm, logger)
return
}

for _, cs := range *codeSystem {
result.CodeSystems = append(result.CodeSystems, &cs)
}

if len(result.CodeSystems) <= defaultPageCount {
defaultPageCount = len(result.CodeSystems)
}

result.PageCount = defaultPageCount
result.CodeSystemsCount = strconv.Itoa(len(result.CodeSystems))

// // retrieve concepts that are part of that code system
// concepts, err := rp.GetCodeSystemConceptsByCodeSystemOID(r.Context(), app.db, codeSystem)
// for _, csc := range *concepts {
// result.CodeSystems = append(result.CodeSystems, &csc)
// }
// result.CodeSystemConcepts = concepts

// for now
result.CodeSystemConceptsCount = strconv.Itoa(0)

// for now
result.ValueSetsCount = strconv.Itoa(0)

w.Header().Set("HX-Push-Url", fmt.Sprintf("/search?type=%s&input=%s", searchType, searchTerm))

component := components.SearchResults(true, "Search", searchTerm, result)
component.Render(r.Context(), w)
}

Expand Down
4 changes: 3 additions & 1 deletion internal/app/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ func (app *Application) routes() http.Handler {
mux.HandleFunc("GET /toggle-banner/{action}", app.handleBannerToggle)
mux.HandleFunc("GET /load-hot-topics", app.getAllHotTopics)

mux.HandleFunc("GET /search-results", app.searchResults)
mux.HandleFunc("POST /api/search", app.formSearch)
mux.HandleFunc("GET /search", app.directSearch)

standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)

return standard.Then(mux)
Expand Down
31 changes: 31 additions & 0 deletions internal/database/models/codesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,34 @@ func GetAllCodeSystems(ctx context.Context, db xo.DB) (*[]xo.CodeSystem, error)
}
return &codeSystems, nil
}

func GetCodeSystemByLikeOID(ctx context.Context, db xo.DB, oid string) (*[]xo.CodeSystem, error) {
wildcard := oid + "%"
const sqlstr = "SELECT * FROM public.code_system WHERE oid LIKE $1"

codeSystems := []xo.CodeSystem{}
rows, err := db.QueryContext(ctx, sqlstr, wildcard)
if err != nil {
return nil, err
}
for rows.Next() {
cs := xo.CodeSystem{}
err := rows.Scan(&cs.Oid, &cs.ID, &cs.Name, &cs.Definitiontext, &cs.Status, &cs.Version, &cs.Versiondescription, &cs.Assigningauthorityversionname, &cs.Distributionsourceversionname, &cs.Distributionsourceid, &cs.Assigningauthorityid, &cs.Codesystemcode, &cs.Sourceurl, &cs.Hl70396identifier, &cs.Legacyflag, &cs.Statusdate, &cs.Acquireddate, &cs.Effectivedate, &cs.Expirydate, &cs.Assigningauthorityreleasedate, &cs.Distributionsourcereleasedate, &cs.Sdocreatedate, &cs.Lastrevisiondate)
if err != nil {
return nil, err
}
codeSystems = append(codeSystems, cs)
}
return &codeSystems, nil
}

type CodeSystemResultRow struct {
CodeSystemsCount string
CodeSystemConceptsCount string
ValueSetsCount string
CodeSystems []*xo.CodeSystem
CodeSystemConcepts []*xo.CodeSystemConcept
ValueSets []*xo.ValueSet
URL string
PageCount int
}
8 changes: 8 additions & 0 deletions internal/database/models/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func (r *Repository) GetCodeSystemByOID(ctx context.Context, oid string) (*xo.Co
return xo.CodeSystemByOid(ctx, r.database, oid)
}

func (r *Repository) GetCodeSystemsByLikeOID(ctx context.Context, oid string) (*[]xo.CodeSystem, error) {
return models.GetCodeSystemByLikeOID(ctx, r.database, oid)
}

// =============================== //
// == CodeSystemConcept methods == //
// =============================== //
Expand All @@ -51,6 +55,10 @@ func (r *Repository) GetCodeSystemConceptsByOID(ctx context.Context, oid string)
return result, err
}

func (r *Repository) GetCodeSystemConceptsByCodeSystemOID(ctx context.Context, db xo.DB, cs *xo.CodeSystem) ([]*xo.CodeSystemConcept, error) {
return xo.CodeSystemConceptByCodesystemoid(ctx, db, cs.Oid)
}

func (r *Repository) GetCodeSystemByValueSetConceptCsOid(ctx context.Context, vsc *xo.ValueSetConcept) (*xo.CodeSystem, error) {
return vsc.CodeSystem(ctx, r.database)
}
Expand Down
35 changes: 33 additions & 2 deletions internal/errors/errors.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package errors

import (
"database/sql"
"errors"
"fmt"
"log/slog"
"net/http"

"github.com/skylight-hq/phinvads-go/internal/ui/components"
)

// Request Errors
Expand Down Expand Up @@ -38,15 +42,42 @@ func (e *DatabaseError) Error() string {
}

func (e *DatabaseError) NoRows(w http.ResponseWriter, r *http.Request, err error, logger *slog.Logger) {
logger.Error(err.Error(), slog.String("method", r.Method), slog.String("uri", r.URL.RequestURI()))
LogError(w, r, err, e.Msg, logger)
http.Error(w, e.Msg, http.StatusBadRequest)
}

func ServerError(w http.ResponseWriter, r *http.Request, err error, logger *slog.Logger) {
logger.Error(err.Error(), slog.String("method", r.Method), slog.String("uri", r.URL.RequestURI()))
LogError(w, r, err, "Server Error", logger)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}

func LogError(w http.ResponseWriter, r *http.Request, err error, errrorText string, logger *slog.Logger) {
logger.Error(err.Error(), slog.String("method", r.Method), slog.String("uri", r.URL.RequestURI()))
}

func SearchError(w http.ResponseWriter, r *http.Request, err error, searchTerm string, logger *slog.Logger) {
if errors.Is(err, sql.ErrNoRows) {
errorString := fmt.Sprintf("Error: Code System %s not found", searchTerm)
dbErr := &DatabaseError{
Err: err,
Msg: errorString,
Method: "getCodeSystemById",
Id: searchTerm,
}

msg := fmt.Sprintf("Method %s returned an error while retrieving %s: %s", dbErr.Method, dbErr.Id, dbErr.Msg)
LogError(w, r, dbErr.Err, msg, logger)

component := components.Error("Search", dbErr.Msg)
component.Render(r.Context(), w)
} else {
LogError(w, r, err, http.StatusText(http.StatusInternalServerError), logger)

component := components.Error("search", err.Error())
component.Render(r.Context(), w)
}
}

// func (app *Application) clientError(w http.ResponseWriter, status int) {
// http.Error(w, http.StatusText(status), status)
// }
36 changes: 30 additions & 6 deletions internal/ui/assets/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ footer .row {
display: inline;
}

.cdc-footer__body-logo {
display: flex;
align-items: center;
}

.site-footer {
padding: 2rem 0;
}
Expand Down Expand Up @@ -298,6 +303,12 @@ footer .row {
line-height: 24px;
}

.usa-form {
display: inline-flex;
max-width: 100%;
width: 100%;
}

.search-results__table {
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.1);
Expand Down Expand Up @@ -340,13 +351,19 @@ footer .row {
.search-results__table .content-row {
display: flex;
align-items: center;
word-wrap: break-word;
}

.search-results__table div.col:not(.check) {
overflow: auto;
}

.content-row.alternate-bg {
background-color: #e2e3e5;
}
.search-results__table .check {
flex-grow: 0;
padding-right: 0.5rem;
}

.search-results__table .row p {
Expand Down Expand Up @@ -379,10 +396,6 @@ footer .row {
padding: 1rem 0.5rem 1rem 0rem;
}

.pagination .page-buttons {
padding-left: 1rem;
}

.page-buttons button {
padding: 0.25rem 0.75rem;
border: 1px solid lightgrey;
Expand Down Expand Up @@ -419,15 +432,26 @@ footer .row {
position: absolute;
}

.download-button button {
.download-button button:disabled {
border: none;
padding: 0.5rem 1rem 0.5rem 0.75rem;
border-radius: 6px;

color: #454545;
background-color: #c9c9c9;
cursor: not-allowed;
opacity: 1;
}

.download-button button:not(:disabled) {
border: none;
background-color: #005ea2;
padding: 0.5rem 1rem 0.5rem 0.75rem;
color: white;
border-radius: 6px;
}

.download-button button:hover {
.download-button button:not(:disabled):hover {
background-color: #0b4778;
color: white;
}
2 changes: 1 addition & 1 deletion internal/ui/components/base.templ
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ templ Base(currentPage string) {
<script src="/assets/js/htmx.min.js"></script>
<script src="/assets/js/uswds-init.min.js"></script>
</head>
<body>
<body id="main-body">
@UsaBanner("close")
@NavBar(currentPage)
<main class="cdc-page-offset">
Expand Down
60 changes: 60 additions & 0 deletions internal/ui/components/code_system_result.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package components

import (
"strconv"
"github.com/skylight-hq/phinvads-go/internal/database/models"
)

templ CodeSystemResult(searchTerm string, searchResults *models.CodeSystemResultRow) {
<div>
@CodeSystemResultsCount(searchResults)
<div class="search-results__table" role="table" aria-label="table">
<div role="rowgroup">
<div class="cdc-header top-header">
<div class="col search-results page-count">Showing {strconv.Itoa(searchResults.PageCount)} of {searchResults.CodeSystemsCount} Code Systems</div>
<div
if searchResults.PageCount >=5 {
class="pagination"
} else {
class="pagination"
hidden
}
>
<div class="col search-results page-buttons">
<button class="active page-button">1</button>
<button class="page-button">2</button>
<button class="page-button">3</button>
<button class="page-button">4</button>
<button class="page-button">5</button>
<div class="button-next">
<button class="page-button">Next</button>
</div>
</div>
</div>
<div class="col search-results download-button">
if searchResults.ValueSetsCount == "0" {
<button disabled aria-disabled="true">
<img src="/assets/img/material-icons/file_download_off.svg">
Download Value Set
</button>
} else {
<button disabled aria-disabled="true">
<img src="/assets/img/material-icons/file_download_off.svg">
Download Value Set
</button>
}
</div>
</div>
@CodeSystemTableHeader()
</div>
<div role="rowgroup">
for idx, item := range searchResults.CodeSystems {
if idx <= 4 {
// modulo check allows alternating background color
@CodeSystemResultRow(idx % 2 != 0, item)
}
}
</div>
</div>
</div>
}
37 changes: 37 additions & 0 deletions internal/ui/components/code_system_result_row.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package components

import "github.com/skylight-hq/phinvads-go/internal/database/models/xo"

templ CodeSystemResultRow(alternate bool, result *xo.CodeSystem) {
<div
if alternate == true {
class="row content-row" role="row"
} else {
class="row content-row alternate-bg" role="row"
}
>
<div class="col check">
<div role="cell">
<input
type="checkbox"
value={result.Codesystemcode}
>
</div>
</div>
<div class="col">
<div role="cell">
<p>{result.Codesystemcode}</p>
</div>
</div>
<div class="col">
<div role="cell">
<p>{result.Name}</p>
</div>
</div>
<div class="col">
<div role="cell">
<p>{result.Oid}</p>
</div>
</div>
</div>
}
Loading

0 comments on commit 724fe91

Please sign in to comment.