Contact Info

sean [at] coreitpro [dot] com gpg key

Mastodon

sc68cal on Libera

JetZig Transportation Management System project - view layer

Writing a view in Jetzig was very similar to writing views in other frameworks like Rails or Django.

The delivery_orders view manages DeliveryOrders, and inherits from the main layout for templating by declaring a layout variable that Jetzig picks up.

The main request object that Jetzig passes as a parameter to view functions, includes a .repo field that is used to connect to the database and execute queries (among other functions).

Index View

pub const layout = "main";

pub fn index(request: *jetzig.Request) !jetzig.View {
    const delivery_orders = jetzig.database.Query(
        .DeliveryOrder,
    ).include(
        .pickup_location,
        .{},
    ).include(
        .dropoff_location,
        .{},
    ).orderBy(
        .{ .id = .descending },
    ).all(request.repo);
    var root = try request.data(.object);
    try root.put("delivery_orders", delivery_orders);
    return request.render(.ok);
}

The main logic for the DeliveryOrders index template is just a table that we iterate through all the delivery_orders results.

<h3>Delivery Orders</h3>
<a class="btn btn-primary" href="/delivery_orders/new" role="button">Create New Delivery Order</a>

<table id="delivery_orders" class="table table-striped">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">Pickup Location</th>
      <th scope="col">Dropoff Location</th>
      <th scope="col">Created At</th>
      <th scope="col">Updated At</th>
    </tr>
  </thead>
  <tbody>
    @for ($.delivery_orders) |order| {
        <tr>
            <td scope="row"><a href="/delivery_orders/{{order.id}}">{{order.id}}</a></td>
            <td><a href="/locations/{{order.pickup_location_id}}">{{order.pickup_location.name}}</a></td>
            <td><a href="/locations/{{order.dropoff_location_id}}">{{order.dropoff_location.name}}</a></td>
            <td>{{order.created_at}}</td>
            <td>{{order.updated_at}}</td>
        </tr>
    }
  </tbody>
</table>

Detail view

The get is very similar to the index but focuses on a single DeliveryOrder and fetches related objects via foreign key. All the containers in the database are also retrieved, in order for additional containers to be added to a DeliveryOrder after it has been created.

pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
    var root = try request.data(.object);
    const delivery_order = jetzig.database.Query(
        .DeliveryOrder,
    ).include(
        .pickup_location,
        .{},
    ).include(
        .dropoff_location,
        .{},
    ).find(
        id,
    ).execute(
        request.repo,
    );
    const delivery_order_containers = jetzig.database.Query(
        .DeliveryOrderContainer,
    ).where(
        .{ .delivery_order_id = id },
    ).all(
        request.repo,
    );
    const containers = jetzig.database.Query(.Container).all(request.repo);
    const attachments = jetzig.database.Query(.Attachment).where(
        .{ .delivery_order_id = id },
    ).all(
        request.repo,
    );
    try root.put("delivery_order", delivery_order);
    try root.put("delivery_order_containers", delivery_order_containers);
    try root.put("containers", containers);
    try root.put("attachments", attachments);
    return request.render(.ok);
}
<span><h2>Delivery Order {{.delivery_order.id}}</h2></span>
<div class="row">
  <div class="col">
    <h3>Pickup</h3>
    <input type="hidden" id="from_location_lat" value="{{.delivery_order.pickup_location.lat}}">
    <input type="hidden" id="from_location_lon" value="{{.delivery_order.pickup_location.lon}}">
    <p><h5>Location Name:</h5></p>
    <p>{{.delivery_order.pickup_location.name }}</p>
    <p><h5>Address:</h5></p>
    <p>{{.delivery_order.pickup_location.address }}</p>
  </div>
  <div class="col">
    <h3>Dropoff</h3>
    <input type="hidden" id="to_location_lat" value="{{.delivery_order.dropoff_location.lat}}">
    <input type="hidden" id="to_location_lon" value="{{.delivery_order.dropoff_location.lon}}">
    <p><h5>Location Name:</h5></p>
    <p>{{.delivery_order.dropoff_location.name }}</p>
    <p><h5>Address:</h5></p>
    <p>{{.delivery_order.dropoff_location.address }}</p>
  </div>
</div>
<div id="map" style="height: 400px;">
</div>
<div>
<h2>Documents</h2>
<table id="attachments" class="table table-striped">
  <thead>
    <tr>
      <th scope="col"></th>
    </tr>
  </thead>
  <tbody>
    @for ($.attachments) |attachment| {
        <tr>
            <td><embed src="{{attachment.url}}" /></td>
        </tr>
    }
  </tbody>
</table>
</div>
<h5>Add Document to Delivery Order</h5>
<form class="row g-3" action="/attachments" method="POST" id="attachments">
    <div class="col-md-6">
        <input type="hidden" name="delivery_order" value="{{.delivery_order.id}}">
        <label for="attachment" class="form-label">Upload document</label>
        <input class="form-control" type="file" name="attachment">
        <input class="form-control form-control-lg" type="submit" value="Upload">
    </div>
</form>
<div>
<h2>Containers</h2>
<table id="containers" class="table table-striped">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">Name</th>
    </tr>
  </thead>
  <tbody>
    @for ($.delivery_order_containers) |container| {
        <tr>
            <td scope="row"><a href="/containers/{{container.id}}">{{container.id}}</a></td>
            <td>{{container.container_number}}</td>
        </tr>
    }
  </tbody>
</table>
</div>
<div>
<h5>Add Container to Delivery Order</h5>
<form class="row g-3" action="/delivery_orders_containers" method="POST" id="delivery_order">
    @partial partials/datalist_from_objects($.containers, "containerOptions")
    <div class="col-md-6">
        <label for="containerInput" class="form-label">Container</label>
        <input class="form-control" list="containerOptions" name="containerInput" placeholder="Type to search...">
        <input type="hidden" name="delivery_order" value="{{.delivery_order.id}}">
        <input type="submit" class="form-control" value="Save">
    </div>
</form>
</div>