Skip to content

Commit

Permalink
feat: implement staff address
Browse files Browse the repository at this point in the history
Signed-off-by: maxwellgithinji <maxwellgithinji@gmail.com>
  • Loading branch information
maxwellgithinji committed Oct 26, 2021
1 parent 2a1612c commit fbc7952
Show file tree
Hide file tree
Showing 27 changed files with 1,778 additions and 529 deletions.
4 changes: 2 additions & 2 deletions gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ models:
FacilityInput:
model:
- github.com/savannahghi/onboarding-service/pkg/onboarding/application/dto.FacilityInput
PINInput:
PinInput:
model:
- github.com/savannahghi/onboarding-service/pkg/onboarding/application/dto.PINInput
- github.com/savannahghi/onboarding-service/pkg/onboarding/application/dto.PinInput
UserProfile:
fields:
roleDetails:
Expand Down
60 changes: 35 additions & 25 deletions pkg/onboarding/application/dto/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ func (i *FacilitySortInput) ToURLValues() (values url.Values) {
type MetricInput struct {

// TODO Metric types should be a controlled list i.e enum
Type enums.MetricType `json:"metric_type"`
Type enums.MetricType `json:"metricType"`

// this will vary by context
// should not identify the user (there's a UID field)
// focus on the actual event
Payload datatypes.JSON `gorm:"column:payload"`
Payload datatypes.JSON `json:"payload"`

Timestamp time.Time `json:"time"`

Expand All @@ -85,34 +85,34 @@ type MetricInput struct {
UID string `json:"uid"`
}

// PINInput represents the PIN input data structure
type PINInput struct {
// PinInput represents the PIN input data structure
type PinInput struct {
PIN string `json:"pin"`
ConfirmedPin string `json:"confirmed_pin"`
ConfirmedPin string `json:"confirmedPin"`
Flavour feedlib.Flavour `json:"flavour"`
}

// LoginInput represents the Login input data structure
type LoginInput struct {
UserID string `json:"user_id"`
UserID string `json:"userID"`
PIN string `json:"pin"`
Flavour feedlib.Flavour `json:"flavour"`
}

// StaffProfileInput contains input required to register a staff
type StaffProfileInput struct {
StaffNumber string
StaffNumber string `json:"staffNumber"`

// Facilities []*domain.Facility // TODO: needs at least one
// Facilities []*domain.Facility `json:"facilities"` // TODO: needs at least one

// A UI switcher optionally toggles the default
// TODO: the list of facilities to switch between is strictly those that the user is assigned to
DefaultFacilityID *string // TODO: required, FK to facility
DefaultFacilityID *string `json:"defaultFacilityID"`

// // there is nothing special about super-admin; just the set of roles they have
// Roles []domain.RoleType `json:"roles"` // TODO: roles are an enum (controlled list), known to both FE and BE

// Addresses []*domain.UserAddress
Addresses []*AddressesInput `json:"addresses"`
}

// ClientProfileInput is used to supply the client profile input
Expand All @@ -122,32 +122,42 @@ type ClientProfileInput struct {

// UserInput is used to supply user input for registration
type UserInput struct {
Username string // @handle, also globally unique; nickname
Username string `json:"username"` // @handle, also globally unique; nickname

DisplayName string // user's preferred display name
DisplayName string `json:"dispalyName"` // user's preferred display name

// TODO Consider making the names optional in DB; validation in frontends
FirstName string // given name
MiddleName string
LastName string
FirstName string `json:"firstName"` // given name
MiddleName string `json:"middleName"`
LastName string `json:"lastName"`

UserType enums.UsersType // TODO enum; e.g client, health care worker
UserType enums.UsersType `json:"userType"`

Gender enumutils.Gender // TODO enum; genders; keep it simple
Gender enumutils.Gender `json:"gender"`

Contacts []*ContactInput // TODO: validate, ensure
Contacts []*ContactInput `json:"contactInput"` // TODO: validate, ensure

// // for the preferred language list, order matters
Languages []enumutils.Language // TODO: turn this into a slice of enums, start small (en, sw)
Flavour feedlib.Flavour
// for the preferred language list, order matters
Languages []enumutils.Language `json:"languages"`
Flavour feedlib.Flavour `json:"flavour"`
}

// ContactInput contains input required to register a user
type ContactInput struct {
Type enums.ContactType
Contact string //TODO Validate: phones are E164, emails are valid
Active bool
Type enums.ContactType `json:"type"`
Contact string `json:"contact"` //TODO Validate: phones are E164, emails are valid
Active bool `json:"active"`
// a user may opt not to be contacted via this contact
// e.g if it's a shared phone owned by a teenager
OptedIn bool
OptedIn bool `json:"optedIn"`
}

// AddressesInput defines the values required when setting up user information
type AddressesInput struct {
Type enums.AddressesType `json:"type"`
Text string `json:"text"` // actual address, can be multi-line
Country enums.CountryType `json:"country"`
PostalCode string `json:"postalCode"`
County enums.CountyType `json:"county"`
Active bool `json:"active"`
}
61 changes: 61 additions & 0 deletions pkg/onboarding/application/enums/counties_of_country.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package enums

import "fmt"

// CountiesOfCountry defines the counties of a country
type CountiesOfCountry struct {
Country CountryType
Counties []CountyType
}

// Create a struct with a combined list of counties of countries
var countiesOfCountries = []CountiesOfCountry{
{
Country: CountryTypeKenya,
Counties: KenyanCounties,
},
// Other CountiesOfCountries
}

// ValidateCountiesOfCountries validates the county passed to a country is valid
func ValidateCountiesOfCountries(country CountryType, county CountyType) error {
// ensure we are working with a correct country type to begin with
if !country.IsValid() {
return fmt.Errorf("failed to validate country: %s", country)
}
// Validate the county too
if !county.IsValid() {
return fmt.Errorf("failed to validate county: %s", county)
}

ok, counties := findSelectedCountryCounties(countiesOfCountries, country)
if !ok {
return fmt.Errorf("failed to find selected country's counties: %s", county)
}

err := findCounty(counties.Counties, county)
if err != nil {
return fmt.Errorf("failed to find county: %s", err)
}
return nil
}

// finds the selected country te ensure it's part of the enum, then return the respective counties it has
func findSelectedCountryCounties(countriesCounties []CountiesOfCountry, countryInput CountryType) (bool, *CountiesOfCountry) {
for i, countryCounty := range countriesCounties {
if countryCounty.Country == countryInput {
return true, &countiesOfCountries[i]
}
}
return false, nil
}

// checks whether the county provided is present in the list of the selected country's counties
func findCounty(counties []CountyType, countyInput CountyType) error {
for _, county := range counties {
if county == countyInput {
return nil
}
}
return fmt.Errorf("failed to find county: %s", countyInput)
}
54 changes: 54 additions & 0 deletions pkg/onboarding/application/enums/country_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package enums

import (
"fmt"
"io"
"strconv"
)

// CountryType defines various countries available
type CountryType string

const (
// CountryTypeKenya defines country type KENYA
CountryTypeKenya CountryType = "KENYA"
// Other countries
)

// AllCountries represents a slice of all countries available
var AllCountries = []CountryType{
CountryTypeKenya,
}

// IsValid returns true if a country type is valid
func (e CountryType) IsValid() bool {
switch e {
case CountryTypeKenya:
return true
}
return false
}

// String converts country type to string.
func (e CountryType) String() string {
return string(e)
}

// UnmarshalGQL converts the supplied value to a country type.
func (e *CountryType) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}

*e = CountryType(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid CountryType", str)
}
return nil
}

// MarshalGQL writes the country type to the supplied writer
func (e CountryType) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}

0 comments on commit fbc7952

Please sign in to comment.