Version 8 #43
| @ -312,6 +312,13 @@ type ListPreferences = | ||||
|         /// How the as-of date should be automatically displayed | ||||
|         AsOfDateDisplay : AsOfDateDisplay | ||||
|     } | ||||
| with | ||||
|      | ||||
|     /// The list of fonts to use when displaying request lists (converts "native" to native font stack) | ||||
|     member this.FontStack = | ||||
|         if this.Fonts = "native" then | ||||
|             """system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif""" | ||||
|         else this.Fonts | ||||
| 
 | ||||
| /// Functions to support list preferences | ||||
| module ListPreferences = | ||||
| @ -323,8 +330,8 @@ module ListPreferences = | ||||
|             DaysToKeepNew       = 7 | ||||
|             LongTermUpdateWeeks = 4 | ||||
|             EmailFromName       = "PrayerTracker" | ||||
|             EmailFromAddress    = "prayer@djs-consulting.com" | ||||
|             Fonts               = "Century Gothic,Tahoma,Luxi Sans,sans-serif" | ||||
|             EmailFromAddress    = "prayer@bitbadger.solutions" | ||||
|             Fonts               = "native" | ||||
|             HeadingColor        = "maroon" | ||||
|             LineColor           = "navy" | ||||
|             HeadingFontSize     = 16 | ||||
|  | ||||
| @ -98,6 +98,15 @@ let expirationTests = | ||||
| [<Tests>] | ||||
| let listPreferencesTests = | ||||
|     testList "ListPreferences" [ | ||||
|         test "FontStack is correct for native fonts" { | ||||
|             Expect.equal ListPreferences.empty.FontStack | ||||
|                 """system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif""" | ||||
|                 "The expected native font stack was incorrect" | ||||
|         } | ||||
|         test "FontStack is correct for specific fonts" { | ||||
|             Expect.equal { ListPreferences.empty with Fonts = "Arial,sans-serif" }.FontStack "Arial,sans-serif" | ||||
|                 "The specified fonts were not returned correctly" | ||||
|         } | ||||
|         test "empty is as expected" { | ||||
|             let mt = ListPreferences.empty | ||||
|             Expect.equal mt.SmallGroupId.Value Guid.Empty "The small group ID should have been an empty GUID" | ||||
| @ -107,7 +116,7 @@ let listPreferencesTests = | ||||
|             Expect.equal mt.EmailFromName "PrayerTracker" "The default e-mail from name should have been PrayerTracker" | ||||
|             Expect.equal mt.EmailFromAddress "prayer@djs-consulting.com" | ||||
|                 "The default e-mail from address should have been prayer@djs-consulting.com" | ||||
|             Expect.equal mt.Fonts "Century Gothic,Tahoma,Luxi Sans,sans-serif" "The default list fonts were incorrect" | ||||
|             Expect.equal mt.Fonts "native" "The default list fonts were incorrect" | ||||
|             Expect.equal mt.HeadingColor "maroon" "The default heading text color should have been maroon" | ||||
|             Expect.equal mt.LineColor "navy" "The default heding line color should have been navy" | ||||
|             Expect.equal mt.HeadingFontSize 16 "The default heading font size should have been 16" | ||||
|  | ||||
| @ -78,6 +78,28 @@ let namedColorList name selected attrs (s : IStringLocalizer) = | ||||
|     |> List.ofSeq | ||||
|     |> select (_name name :: attrs) | ||||
| 
 | ||||
| /// Convert a named color to its hex notation | ||||
| let colorToHex (color : string) = | ||||
|     match color with | ||||
|     | it when it.StartsWith "#" -> color | ||||
|     | "aqua"    -> "#00ffff" | ||||
|     | "black"   -> "#000000" | ||||
|     | "blue"    -> "#0000ff" | ||||
|     | "fuchsia" -> "#ff00ff" | ||||
|     | "gray"    -> "#808080" | ||||
|     | "green"   -> "#008000" | ||||
|     | "lime"    -> "#00ff00" | ||||
|     | "maroon"  -> "#800000" | ||||
|     | "navy"    -> "#000080" | ||||
|     | "olive"   -> "#808000" | ||||
|     | "purple"  -> "#800080" | ||||
|     | "red"     -> "#ff0000" | ||||
|     | "silver"  -> "#c0c0c0" | ||||
|     | "teal"    -> "#008080" | ||||
|     | "white"   -> "#ffffff" | ||||
|     | "yellow"  -> "#ffff00" | ||||
|     | it        -> it | ||||
|      | ||||
| /// Generate an input[type=radio] that is selected if its value is the current value | ||||
| let radio name domId value current = | ||||
|     input [ _type "radio" | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| module PrayerTracker.Views.PrayerRequest | ||||
| 
 | ||||
| open System | ||||
| open System.Globalization | ||||
| open System.IO | ||||
| open Giraffe | ||||
| open Giraffe.ViewEngine | ||||
| @ -17,7 +17,11 @@ let edit (model : EditRequest) today ctx viewInfo = | ||||
|     let s         = I18N.localizer.Force () | ||||
|     let pageTitle = if model.IsNew then "Add a New Request" else "Edit Request" | ||||
|     let vi        = AppViewInfo.withOnLoadScript "PT.initCKEditor" viewInfo | ||||
|     form [ _action "/prayer-request/save"; _method "post"; _class "pt-center-columns"; Target.content ] [ | ||||
|     form [ _action   "/prayer-request/save" | ||||
|            _method   "post" | ||||
|            _class    "pt-center-columns" | ||||
|            _onsubmit "PT.updateCKEditor()" | ||||
|            Target.content ] [ | ||||
|         csrfToken ctx | ||||
|         inputField "hidden" (nameof model.RequestId) model.RequestId [] | ||||
|         div [ _fieldRow ] [ | ||||
| @ -79,7 +83,7 @@ let email model viewInfo = | ||||
|     let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}""" | ||||
|     let prefs     = model.SmallGroup.Preferences | ||||
|     let addresses = model.Recipients |> List.map (fun mbr -> $"{mbr.Name} <{mbr.Email}>") |> String.concat ", " | ||||
|     [   p [ _style $"font-family:{prefs.Fonts};font-size:%i{prefs.TextFontSize}pt;" ] [ | ||||
|     [   p [ _style $"font-family:{prefs.FontStack};font-size:%i{prefs.TextFontSize}pt;" ] [ | ||||
|             locStr s["The request list was sent to the following people, via individual e-mails"] | ||||
|             rawText ":" | ||||
|             br [] | ||||
| @ -202,7 +206,7 @@ let maintain (model : MaintainRequests) (ctx : HttpContext) viewInfo = | ||||
|                     ] | ||||
|                 ] | ||||
|                 div [ updateClass ] [ | ||||
|                     str (req.UpdatedDate.ToString(s["MMMM d, yyyy"].Value, Globalization.CultureInfo.CurrentUICulture)) | ||||
|                     str (req.UpdatedDate.ToString(s["MMMM d, yyyy"].Value, CultureInfo.CurrentUICulture)) | ||||
|                 ] | ||||
|                 div [ _class "cell" ] [ locStr types[req.RequestType] ] | ||||
|                 div [ expiredClass ] [ str (match req.Requestor with Some r -> r | None -> " ") ] | ||||
| @ -300,7 +304,7 @@ let print model version = | ||||
|         rawText (model.AsHtml s) | ||||
|         br [] | ||||
|         hr [] | ||||
|         div [ _style $"font-size:70%%;font-family:{model.SmallGroup.Preferences.Fonts};" ] [ | ||||
|         div [ _style $"font-size:70%%;font-family:{model.SmallGroup.Preferences.FontStack};" ] [ | ||||
|             img [ _src $"""/img/{s["footer_en"].Value}.png""" | ||||
|                   _style "vertical-align:text-bottom;" | ||||
|                   _alt imgAlt | ||||
| @ -317,7 +321,7 @@ let view model viewInfo = | ||||
|     let s         = I18N.localizer.Force () | ||||
|     let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}""" | ||||
|     let spacer    = rawText "       " | ||||
|     let dtString  = model.Date.ToString ("yyyy-MM-dd", null) // TODO: this should be invariant | ||||
|     let dtString  = model.Date.ToString ("yyyy-MM-dd", CultureInfo.InvariantCulture) | ||||
|     [   div [ _class "pt-center-text" ] [ | ||||
|             br [] | ||||
|             a [ _class  "pt-icon-link" | ||||
| @ -333,7 +337,7 @@ let view model viewInfo = | ||||
|                         if date.DayOfWeek = IsoDayOfWeek.Sunday then date else findSunday (date.PlusDays 1) | ||||
|                     let sunday = findSunday model.Date | ||||
|                     a [ _class "pt-icon-link" | ||||
|                         _href  $"""/prayer-requests/view/{sunday.ToString ("yyyy-MM-dd", null)}""" // TODO: make invariant | ||||
|                         _href  $"""/prayer-requests/view/{sunday.ToString ("yyyy-MM-dd", CultureInfo.InvariantCulture)}""" | ||||
|                         _title s["List for Next Sunday"].Value ] [ | ||||
|                         icon "update"; rawText "  "; locStr s["List for Next Sunday"] | ||||
|                     ] | ||||
|  | ||||
| @ -14,7 +14,11 @@ let announcement isAdmin ctx viewInfo = | ||||
|     let model    = { SendToClass = ""; Text = ""; AddToRequestList = None; RequestType = None } | ||||
|     let reqTypes = ReferenceList.requestTypeList s | ||||
|     let vi       = AppViewInfo.withOnLoadScript "PT.smallGroup.announcement.onPageLoad" viewInfo | ||||
|     form [ _action "/small-group/announcement/send"; _method "post"; _class "pt-center-columns"; Target.content ] [ | ||||
|     form [ _action "/small-group/announcement/send" | ||||
|            _method "post" | ||||
|            _class "pt-center-columns" | ||||
|            _onsubmit "PT.updateCKEditor()" | ||||
|            Target.content ] [ | ||||
|         csrfToken ctx | ||||
|         div [ _fieldRow ] [ | ||||
|             div [ _inputFieldWith [ "pt-editor" ] ] [ | ||||
| @ -461,7 +465,7 @@ let preferences (model : EditPreferences) ctx viewInfo = | ||||
|                             input [ _type  "color"  | ||||
|                                     _name  (nameof model.LineColor) | ||||
|                                     _id    $"{nameof model.LineColor}_Color" | ||||
|                                     _value model.LineColor // TODO: convert to hex or skip if named | ||||
|                                     _value (colorToHex model.LineColor) | ||||
|                                     if not (model.LineColor.StartsWith "#") then _disabled ] | ||||
|                         ] | ||||
|                     ] | ||||
| @ -483,7 +487,7 @@ let preferences (model : EditPreferences) ctx viewInfo = | ||||
|                             input [ _type  "color" | ||||
|                                     _name  (nameof model.HeadingColor) | ||||
|                                     _id    $"{nameof model.HeadingColor}_Color" | ||||
|                                     _value model.HeadingColor // TODO: convert to hex or skip if named | ||||
|                                     _value (colorToHex model.HeadingColor) | ||||
|                                     if not (model.HeadingColor.StartsWith "#") then _disabled ] | ||||
|                         ] | ||||
|                     ] | ||||
|  | ||||
| @ -778,7 +778,7 @@ with | ||||
|         let p        = this.SmallGroup.Preferences | ||||
|         let asOfSize = Math.Round (float p.TextFontSize * 0.8, 2) | ||||
|         [   if this.ShowHeader then | ||||
|                 div [ _style $"text-align:center;font-family:{p.Fonts}" ] [ | ||||
|                 div [ _style $"text-align:center;font-family:{p.FontStack}" ] [ | ||||
|                     span [ _style $"font-size:%i{p.HeadingFontSize}pt;" ] [ | ||||
|                         strong [] [ str s["Prayer Requests"].Value ] | ||||
|                     ] | ||||
| @ -792,7 +792,7 @@ with | ||||
|                 br [] | ||||
|             for _, name, reqs in this.RequestsByType s do | ||||
|                 div [ _style "padding-left:10px;padding-bottom:.5em;" ] [ | ||||
|                     table [ _style $"font-family:{p.Fonts};page-break-inside:avoid;" ] [ | ||||
|                     table [ _style $"font-family:{p.FontStack};page-break-inside:avoid;" ] [ | ||||
|                         tr [] [ | ||||
|                             td [ _style $"font-size:%i{p.HeadingFontSize}pt;color:{p.HeadingColor};padding:3px 0;border-top:solid 3px {p.LineColor};border-bottom:solid 3px {p.LineColor};font-weight:bold;" ] [ | ||||
|                                 rawText "    "; str name.Value; rawText "    " | ||||
| @ -804,7 +804,7 @@ with | ||||
|                 reqs | ||||
|                 |> List.map (fun req -> | ||||
|                     let bullet = if this.IsNew req then "circle" else "disc" | ||||
|                     li [ _style $"list-style-type:{bullet};font-family:{p.Fonts};font-size:%i{p.TextFontSize}pt;padding-bottom:.25em;" ] [ | ||||
|                     li [ _style $"list-style-type:{bullet};font-family:{p.FontStack};font-size:%i{p.TextFontSize}pt;padding-bottom:.25em;" ] [ | ||||
|                         match req.Requestor with | ||||
|                         | Some r when r <> "" -> | ||||
|                             strong [] [ str r ] | ||||
|  | ||||
| @ -260,7 +260,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=> | ||||
|         // Reformat the text to use the class's font stylings | ||||
|         let requestText = ckEditorToText model.Text | ||||
|         let htmlText = | ||||
|             p [ _style $"font-family:{pref.Fonts};font-size:%d{pref.TextFontSize}pt;" ] [ rawText requestText ] | ||||
|             p [ _style $"font-family:{pref.FontStack};font-size:%d{pref.TextFontSize}pt;" ] [ rawText requestText ] | ||||
|             |> renderHtmlNode | ||||
|         let plainText = (htmlToPlainText >> wordWrap 74) htmlText | ||||
|         // Send the e-mails | ||||
|  | ||||
| @ -86,9 +86,17 @@ this.PT = { | ||||
|   initCKEditor() { | ||||
|     ClassicEditor | ||||
|       .create(document.querySelector("#Text")) | ||||
|       .then(editor => window.ckEditor = editor) | ||||
|       .catch(console.error) | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Instruct the current CKEditor element to update its source (needed as htmx does not fire the submit event) | ||||
|    */ | ||||
|   updateCKEditor() { | ||||
|     window.ckEditor.updateElement() | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Scripts for pages served by the Church controller | ||||
|    */ | ||||
|  | ||||
| @ -29,11 +29,14 @@ ALTER TABLE pt."ListPreference" RENAME COLUMN "PageSize" TO page_size; | ||||
| ALTER TABLE pt."ListPreference" RENAME COLUMN "AsOfDateDisplay" TO as_of_date_display; | ||||
| ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "PK_ListPreference" TO pk_list_preference; | ||||
| ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_SmallGroup_SmallGroupId" TO fk_list_preference_small_group_id; | ||||
| ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_TimeZone_TimeZoneId" TO fk_list_preference_time_zone_id; | ||||
| ALTER TABLE pt."ListPreference" DROP   CONSTRAINT "FK_ListPreference_TimeZone_TimeZoneId"; | ||||
| ALTER TABLE pt."ListPreference" RENAME TO list_preference; | ||||
| 
 | ||||
| ALTER INDEX pt."IX_ListPreference_TimeZoneId" RENAME TO ix_list_preference_time_zone_id; | ||||
| 
 | ||||
| ALTER TABLE pt.list_preference ALTER COLUMN email_from_address SET DEFAULT 'prayer@bitbadger.solutions'; | ||||
| ALTER TABLE pt.list_preference ALTER COLUMN fonts SET DEFAULT 'native'; | ||||
| 
 | ||||
| -- Small Group Member | ||||
| ALTER TABLE pt."Member" RENAME COLUMN "MemberId" TO id; | ||||
| ALTER TABLE pt."Member" RENAME COLUMN "SmallGroupId" TO small_group_id; | ||||
| @ -77,7 +80,6 @@ ALTER TABLE pt."SmallGroup" RENAME TO small_group; | ||||
| ALTER INDEX pt."IX_SmallGroup_ChurchId" RENAME TO ix_small_group_church_id; | ||||
| 
 | ||||
| -- Time Zone (goes away) | ||||
| ALTER TABLE pt.list_preference DROP CONSTRAINT fk_list_preference_time_zone_id; | ||||
| DROP TABLE pt."TimeZone"; | ||||
| 
 | ||||
| -- User | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user