Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/src/database/facilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func (db *DB) CreateFacility(facility *models.Facility) error {

func (db *DB) UpdateFacility(facility *models.Facility, id uint) error {
facility.ID = id
if err := Validate().Struct(facility); err != nil {
log.Error("Validation Error")
return NewDBError(err, "facilities")
}
if err := db.Save(&facility).Error; err != nil {
log.WithField("facility_id", facility.ID).Error("error updating facility name database/UpdateFacility")
return newUpdateDBError(err, "facilities")
Expand Down
8 changes: 8 additions & 0 deletions backend/src/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,14 @@ func (srv *Server) handleResetPassword(w http.ResponseWriter, r *http.Request, l
}
log.add("username_to_reset", user.Username)
if claims.Role == models.SystemAdmin && form.FacilityName != "" {
if strings.TrimSpace(form.Timezone) == "" {
tx.Rollback()
return newBadRequestServiceError(errors.New("timezone is required"), "Timezone is required")
}
if _, err := time.LoadLocation(form.Timezone); err != nil {
tx.Rollback()
return newBadRequestServiceError(err, "Invalid timezone")
}
facility := models.Facility{Name: form.FacilityName, Timezone: form.Timezone}
if err := srv.WithUserContext(r).UpdateFacility(&facility, 1); err != nil {
tx.Rollback()
Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/facilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type FacilityWithStats struct {
type Facility struct {
DatabaseFields
Name string `gorm:"size:255;not null" json:"name"`
Timezone string `gorm:"size:255;not null" json:"timezone" validate:"timezone"`
Timezone string `gorm:"size:255;not null" json:"timezone" validate:"required,timezone"`

Users []User `gorm:"foreignKey:FacilityID;references:ID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"-"`
Programs []Program `json:"programs" gorm:"-"`
Expand Down
31 changes: 28 additions & 3 deletions frontend/src/components/forms/ChangePasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ interface Inputs {
timezone: string;
}

function getDefaultTimezone(): string {
const allowed = Object.values(Timezones) as string[];
const browserTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
return allowed.includes(browserTz) ? browserTz : Timezones.CST;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

export default function ChangePasswordForm() {
const navigate = useNavigate();
const [errorMessage, setErrorMessage] = useState('');
Expand All @@ -36,7 +42,9 @@ export default function ChangePasswordForm() {
reset,
setValue,
formState: { errors }
} = useForm<Inputs>();
} = useForm<Inputs>({
defaultValues: { timezone: getDefaultTimezone() }
});

useEffect(() => {
const getUser = async () => {
Expand All @@ -55,11 +63,14 @@ export default function ChangePasswordForm() {
const password = useWatch({ control, name: 'password' });
const confirm = useWatch({ control, name: 'confirm' });
const facility = useWatch({ control, name: 'facility_name' });
const timezone = useWatch({ control, name: 'timezone' });

const isLengthValid = password && password.length >= 8;
const hasNumber = /\d/.test(password);
const passwordsMatch = password === confirm;
const isValid = isLengthValid && hasNumber && passwordsMatch;
const validTimezone = !isFirstLogin || timezone;
const isValid =
isLengthValid && hasNumber && passwordsMatch && validTimezone;
const validFacility =
facility && facility.length > 2 && facility.trim().length > 2;

Expand Down Expand Up @@ -207,9 +218,18 @@ export default function ChangePasswordForm() {
<Label htmlFor="timezone" className="text-foreground">
Timezone
</Label>
<Input
type="hidden"
{...register('timezone', {
required: 'Timezone is required'
})}
/>
<Select
value={timezone}
onValueChange={(value) =>
setValue('timezone', value)
setValue('timezone', value, {
shouldValidate: true
})
}
>
<SelectTrigger>
Expand All @@ -225,6 +245,11 @@ export default function ChangePasswordForm() {
)}
</SelectContent>
</Select>
{errors.timezone && (
<p className="text-sm text-destructive">
{errors.timezone.message}
</p>
)}
</div>
</>
)}
Expand Down
Loading