@@ -169,8 +169,8 @@ export function immutable_to_list<T, P>(
169169) : T extends TypedMap < infer S >
170170 ? S [ ]
171171 : T extends Map < string , infer S >
172- ? S [ ]
173- : any ;
172+ ? S [ ]
173+ : any ;
174174export function immutable_to_list ( x : any , primary_key ?) : any {
175175 if ( x == null || x == undefined ) {
176176 return ;
@@ -242,34 +242,56 @@ export function order_list<T extends { deleted: boolean }>(opts: {
242242 return { list, deleted : x , num_deleted : sorted_deleted . length } ;
243243}
244244
245- const sort_on_string_field = ( field ) => ( a , b ) =>
246- cmp ( a [ field ] . toLowerCase ( ) , b [ field ] . toLowerCase ( ) ) ;
245+ const cmp_strings = ( a , b , field ) => {
246+ return cmp ( a [ field ] ?. toLowerCase ( ) ?? "" , b [ field ] ?. toLowerCase ( ) ?? "" ) ;
247+ } ;
247248
248- const sort_on_numerical_field = ( field ) => ( a , b ) =>
249- cmp ( a [ field ] * - 1 , b [ field ] * - 1 ) ;
249+ // first sort by domain, then address at that domain... since there will be many students
250+ // at same domain, and 'a@b.c' > 'a3@b.c' > 'a2@b.c' is true but not helpful
251+ const cmp_email = ( a , b ) => {
252+ const v = a . split ( "@" ) ;
253+ const w = b . split ( "@" ) ;
254+ const c = cmp ( v [ 1 ] , w [ 1 ] ) ;
255+ if ( c ) {
256+ return c ;
257+ }
258+ return cmp ( v [ 0 ] , w [ 0 ] ) ;
259+ } ;
250260
251- export enum StudentField {
252- email = "email" ,
253- first_name = "first_name" ,
254- last_name = "last_name" ,
255- last_active = "last_active" ,
256- hosting = "hosting" ,
257- }
261+ const sort_on_string_field = ( field , field2 ) => ( a , b ) => {
262+ const c =
263+ field == "email_address"
264+ ? cmp_email ( a [ field ] , b [ field ] )
265+ : cmp_strings ( a , b , field ) ;
266+ return c != 0 ? c : cmp_strings ( a , b , field2 ) ;
267+ } ;
268+
269+ const sort_on_numerical_field = ( field , field2 ) => ( a , b ) => {
270+ const c = cmp ( ( a [ field ] ?? 0 ) * - 1 , ( b [ field ] ?? 0 ) * - 1 ) ;
271+ return c != 0 ? c : cmp_strings ( a , b , field2 ) ;
272+ } ;
273+
274+ type StudentField =
275+ | "email"
276+ | "first_name"
277+ | "last_name"
278+ | "last_active"
279+ | "hosting" ;
258280
259281export function pick_student_sorter < T extends { column_name : StudentField } > (
260282 sort : T ,
261283) {
262284 switch ( sort . column_name ) {
263285 case "email" :
264- return sort_on_string_field ( "email_address" ) ;
286+ return sort_on_string_field ( "email_address" , "last_name" ) ;
265287 case "first_name" :
266- return sort_on_string_field ( "first_name" ) ;
288+ return sort_on_string_field ( "first_name" , "last_name" ) ;
267289 case "last_name" :
268- return sort_on_string_field ( "last_name" ) ;
290+ return sort_on_string_field ( "last_name" , "first_name" ) ;
269291 case "last_active" :
270- return sort_on_numerical_field ( "last_active" ) ;
292+ return sort_on_numerical_field ( "last_active" , "last_name" ) ;
271293 case "hosting" :
272- return sort_on_string_field ( "hosting" ) ;
294+ return sort_on_string_field ( "hosting" , "email_address" ) ;
273295 }
274296}
275297
0 commit comments