diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..8d7f889 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,2 @@ +NEXT_PUBLIC_VERSION="0.1.0" +NEXT_PUBLIC_API_URL="https://rms.witel.ir" \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..121cefd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": ["next/core-web-vitals","prettier"] } diff --git a/.gitignore b/.gitignore index 2d5bbdd..19f7fa0 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ node_modules cypress/videos cypress/screenshots .next -.env* +.env.local .env .idea package-lock.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..7eeebb6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 120, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "arrowParens": "always", + "endOfLine": "crlf" +} \ No newline at end of file diff --git a/editorconfig b/editorconfig deleted file mode 100644 index 05e5a39..0000000 --- a/editorconfig +++ /dev/null @@ -1,485 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = crlf -indent_size = 4 -indent_style = space -insert_final_newline = false -max_line_length = 120 -tab_width = 4 -ij_continuation_indent_size = 4 -ij_formatter_off_tag = @formatter:off -ij_formatter_on_tag = @formatter:on -ij_formatter_tags_enabled = true -ij_smart_tabs = false -ij_visual_guides = none -ij_wrap_on_typing = false - -[*.css] -ij_css_align_closing_brace_with_properties = false -ij_css_blank_lines_around_nested_selector = 1 -ij_css_blank_lines_between_blocks = 1 -ij_css_block_comment_add_space = false -ij_css_brace_placement = end_of_line -ij_css_enforce_quotes_on_format = false -ij_css_hex_color_long_format = false -ij_css_hex_color_lower_case = false -ij_css_hex_color_short_format = false -ij_css_hex_color_upper_case = false -ij_css_keep_blank_lines_in_code = 2 -ij_css_keep_indents_on_empty_lines = false -ij_css_keep_single_line_blocks = false -ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow -ij_css_space_after_colon = true -ij_css_space_before_opening_brace = true -ij_css_use_double_quotes = true -ij_css_value_alignment = do_not_align - -[*.sass] -indent_size = 2 -ij_sass_align_closing_brace_with_properties = false -ij_sass_blank_lines_around_nested_selector = 1 -ij_sass_blank_lines_between_blocks = 1 -ij_sass_brace_placement = 0 -ij_sass_enforce_quotes_on_format = false -ij_sass_hex_color_long_format = false -ij_sass_hex_color_lower_case = false -ij_sass_hex_color_short_format = false -ij_sass_hex_color_upper_case = false -ij_sass_keep_blank_lines_in_code = 2 -ij_sass_keep_indents_on_empty_lines = false -ij_sass_keep_single_line_blocks = false -ij_sass_line_comment_add_space = false -ij_sass_line_comment_at_first_column = false -ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow -ij_sass_space_after_colon = true -ij_sass_space_before_opening_brace = true -ij_sass_use_double_quotes = true -ij_sass_value_alignment = 0 - -[*.scss] -indent_size = 2 -ij_scss_align_closing_brace_with_properties = false -ij_scss_blank_lines_around_nested_selector = 1 -ij_scss_blank_lines_between_blocks = 1 -ij_scss_block_comment_add_space = false -ij_scss_brace_placement = 0 -ij_scss_enforce_quotes_on_format = false -ij_scss_hex_color_long_format = false -ij_scss_hex_color_lower_case = false -ij_scss_hex_color_short_format = false -ij_scss_hex_color_upper_case = false -ij_scss_keep_blank_lines_in_code = 2 -ij_scss_keep_indents_on_empty_lines = false -ij_scss_keep_single_line_blocks = false -ij_scss_line_comment_add_space = false -ij_scss_line_comment_at_first_column = false -ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow -ij_scss_space_after_colon = true -ij_scss_space_before_opening_brace = true -ij_scss_use_double_quotes = true -ij_scss_value_alignment = 0 - -[{*.ats,*.cts,*.mts,*.ts}] -ij_continuation_indent_size = 4 -ij_typescript_align_imports = false -ij_typescript_align_multiline_array_initializer_expression = false -ij_typescript_align_multiline_binary_operation = false -ij_typescript_align_multiline_chained_methods = false -ij_typescript_align_multiline_extends_list = false -ij_typescript_align_multiline_for = true -ij_typescript_align_multiline_parameters = true -ij_typescript_align_multiline_parameters_in_calls = false -ij_typescript_align_multiline_ternary_operation = false -ij_typescript_align_object_properties = 0 -ij_typescript_align_union_types = false -ij_typescript_align_var_statements = 0 -ij_typescript_array_initializer_new_line_after_left_brace = false -ij_typescript_array_initializer_right_brace_on_new_line = false -ij_typescript_array_initializer_wrap = off -ij_typescript_assignment_wrap = off -ij_typescript_binary_operation_sign_on_next_line = false -ij_typescript_binary_operation_wrap = off -ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** -ij_typescript_blank_lines_after_imports = 1 -ij_typescript_blank_lines_around_class = 1 -ij_typescript_blank_lines_around_field = 0 -ij_typescript_blank_lines_around_field_in_interface = 0 -ij_typescript_blank_lines_around_function = 1 -ij_typescript_blank_lines_around_method = 1 -ij_typescript_blank_lines_around_method_in_interface = 1 -ij_typescript_block_brace_style = end_of_line -ij_typescript_block_comment_add_space = false -ij_typescript_block_comment_at_first_column = true -ij_typescript_call_parameters_new_line_after_left_paren = false -ij_typescript_call_parameters_right_paren_on_new_line = false -ij_typescript_call_parameters_wrap = off -ij_typescript_catch_on_new_line = false -ij_typescript_chained_call_dot_on_new_line = true -ij_typescript_class_brace_style = end_of_line -ij_typescript_comma_on_new_line = false -ij_typescript_do_while_brace_force = never -ij_typescript_else_on_new_line = false -ij_typescript_enforce_trailing_comma = keep -ij_typescript_enum_constants_wrap = on_every_item -ij_typescript_extends_keyword_wrap = off -ij_typescript_extends_list_wrap = off -ij_typescript_field_prefix = _ -ij_typescript_file_name_style = relaxed -ij_typescript_finally_on_new_line = false -ij_typescript_for_brace_force = never -ij_typescript_for_statement_new_line_after_left_paren = false -ij_typescript_for_statement_right_paren_on_new_line = false -ij_typescript_for_statement_wrap = off -ij_typescript_force_quote_style = false -ij_typescript_force_semicolon_style = false -ij_typescript_function_expression_brace_style = end_of_line -ij_typescript_if_brace_force = never -ij_typescript_import_merge_members = global -ij_typescript_import_prefer_absolute_path = global -ij_typescript_import_sort_members = true -ij_typescript_import_sort_module_name = false -ij_typescript_import_use_node_resolution = true -ij_typescript_imports_wrap = on_every_item -ij_typescript_indent_case_from_switch = true -ij_typescript_indent_chained_calls = true -ij_typescript_indent_package_children = 0 -ij_typescript_jsdoc_include_types = false -ij_typescript_jsx_attribute_value = braces -ij_typescript_keep_blank_lines_in_code = 2 -ij_typescript_keep_first_column_comment = true -ij_typescript_keep_indents_on_empty_lines = false -ij_typescript_keep_line_breaks = true -ij_typescript_keep_simple_blocks_in_one_line = false -ij_typescript_keep_simple_methods_in_one_line = false -ij_typescript_line_comment_add_space = true -ij_typescript_line_comment_at_first_column = false -ij_typescript_method_brace_style = end_of_line -ij_typescript_method_call_chain_wrap = off -ij_typescript_method_parameters_new_line_after_left_paren = false -ij_typescript_method_parameters_right_paren_on_new_line = false -ij_typescript_method_parameters_wrap = off -ij_typescript_object_literal_wrap = on_every_item -ij_typescript_object_types_wrap = on_every_item -ij_typescript_parentheses_expression_new_line_after_left_paren = false -ij_typescript_parentheses_expression_right_paren_on_new_line = false -ij_typescript_place_assignment_sign_on_next_line = false -ij_typescript_prefer_as_type_cast = false -ij_typescript_prefer_explicit_types_function_expression_returns = false -ij_typescript_prefer_explicit_types_function_returns = false -ij_typescript_prefer_explicit_types_vars_fields = false -ij_typescript_prefer_parameters_wrap = false -ij_typescript_reformat_c_style_comments = false -ij_typescript_space_after_colon = true -ij_typescript_space_after_comma = true -ij_typescript_space_after_dots_in_rest_parameter = false -ij_typescript_space_after_generator_mult = true -ij_typescript_space_after_property_colon = true -ij_typescript_space_after_quest = true -ij_typescript_space_after_type_colon = true -ij_typescript_space_after_unary_not = false -ij_typescript_space_before_async_arrow_lparen = true -ij_typescript_space_before_catch_keyword = true -ij_typescript_space_before_catch_left_brace = true -ij_typescript_space_before_catch_parentheses = true -ij_typescript_space_before_class_lbrace = true -ij_typescript_space_before_class_left_brace = true -ij_typescript_space_before_colon = true -ij_typescript_space_before_comma = false -ij_typescript_space_before_do_left_brace = true -ij_typescript_space_before_else_keyword = true -ij_typescript_space_before_else_left_brace = true -ij_typescript_space_before_finally_keyword = true -ij_typescript_space_before_finally_left_brace = true -ij_typescript_space_before_for_left_brace = true -ij_typescript_space_before_for_parentheses = true -ij_typescript_space_before_for_semicolon = false -ij_typescript_space_before_function_left_parenth = true -ij_typescript_space_before_generator_mult = false -ij_typescript_space_before_if_left_brace = true -ij_typescript_space_before_if_parentheses = true -ij_typescript_space_before_method_call_parentheses = false -ij_typescript_space_before_method_left_brace = true -ij_typescript_space_before_method_parentheses = false -ij_typescript_space_before_property_colon = false -ij_typescript_space_before_quest = true -ij_typescript_space_before_switch_left_brace = true -ij_typescript_space_before_switch_parentheses = true -ij_typescript_space_before_try_left_brace = true -ij_typescript_space_before_type_colon = false -ij_typescript_space_before_unary_not = false -ij_typescript_space_before_while_keyword = true -ij_typescript_space_before_while_left_brace = true -ij_typescript_space_before_while_parentheses = true -ij_typescript_spaces_around_additive_operators = true -ij_typescript_spaces_around_arrow_function_operator = true -ij_typescript_spaces_around_assignment_operators = true -ij_typescript_spaces_around_bitwise_operators = true -ij_typescript_spaces_around_equality_operators = true -ij_typescript_spaces_around_logical_operators = true -ij_typescript_spaces_around_multiplicative_operators = true -ij_typescript_spaces_around_relational_operators = true -ij_typescript_spaces_around_shift_operators = true -ij_typescript_spaces_around_unary_operator = false -ij_typescript_spaces_within_array_initializer_brackets = false -ij_typescript_spaces_within_brackets = false -ij_typescript_spaces_within_catch_parentheses = false -ij_typescript_spaces_within_for_parentheses = false -ij_typescript_spaces_within_if_parentheses = false -ij_typescript_spaces_within_imports = false -ij_typescript_spaces_within_interpolation_expressions = false -ij_typescript_spaces_within_method_call_parentheses = false -ij_typescript_spaces_within_method_parentheses = false -ij_typescript_spaces_within_object_literal_braces = false -ij_typescript_spaces_within_object_type_braces = true -ij_typescript_spaces_within_parentheses = false -ij_typescript_spaces_within_switch_parentheses = false -ij_typescript_spaces_within_type_assertion = false -ij_typescript_spaces_within_union_types = true -ij_typescript_spaces_within_while_parentheses = false -ij_typescript_special_else_if_treatment = true -ij_typescript_ternary_operation_signs_on_next_line = false -ij_typescript_ternary_operation_wrap = off -ij_typescript_union_types_wrap = on_every_item -ij_typescript_use_chained_calls_group_indents = false -ij_typescript_use_double_quotes = true -ij_typescript_use_explicit_js_extension = auto -ij_typescript_use_path_mapping = always -ij_typescript_use_public_modifier = false -ij_typescript_use_semicolon_after_statement = true -ij_typescript_var_declaration_wrap = normal -ij_typescript_while_brace_force = never -ij_typescript_while_on_new_line = false -ij_typescript_wrap_comments = false - -[{*.cjs,*.js}] -ij_continuation_indent_size = 4 -ij_javascript_align_imports = false -ij_javascript_align_multiline_array_initializer_expression = false -ij_javascript_align_multiline_binary_operation = false -ij_javascript_align_multiline_chained_methods = false -ij_javascript_align_multiline_extends_list = false -ij_javascript_align_multiline_for = true -ij_javascript_align_multiline_parameters = true -ij_javascript_align_multiline_parameters_in_calls = false -ij_javascript_align_multiline_ternary_operation = false -ij_javascript_align_object_properties = 0 -ij_javascript_align_union_types = false -ij_javascript_align_var_statements = 0 -ij_javascript_array_initializer_new_line_after_left_brace = false -ij_javascript_array_initializer_right_brace_on_new_line = false -ij_javascript_array_initializer_wrap = off -ij_javascript_assignment_wrap = off -ij_javascript_binary_operation_sign_on_next_line = false -ij_javascript_binary_operation_wrap = off -ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** -ij_javascript_blank_lines_after_imports = 1 -ij_javascript_blank_lines_around_class = 1 -ij_javascript_blank_lines_around_field = 0 -ij_javascript_blank_lines_around_function = 1 -ij_javascript_blank_lines_around_method = 1 -ij_javascript_block_brace_style = end_of_line -ij_javascript_block_comment_add_space = false -ij_javascript_block_comment_at_first_column = true -ij_javascript_call_parameters_new_line_after_left_paren = false -ij_javascript_call_parameters_right_paren_on_new_line = false -ij_javascript_call_parameters_wrap = off -ij_javascript_catch_on_new_line = false -ij_javascript_chained_call_dot_on_new_line = true -ij_javascript_class_brace_style = end_of_line -ij_javascript_comma_on_new_line = false -ij_javascript_do_while_brace_force = never -ij_javascript_else_on_new_line = false -ij_javascript_enforce_trailing_comma = keep -ij_javascript_extends_keyword_wrap = off -ij_javascript_extends_list_wrap = off -ij_javascript_field_prefix = _ -ij_javascript_file_name_style = relaxed -ij_javascript_finally_on_new_line = false -ij_javascript_for_brace_force = never -ij_javascript_for_statement_new_line_after_left_paren = false -ij_javascript_for_statement_right_paren_on_new_line = false -ij_javascript_for_statement_wrap = off -ij_javascript_force_quote_style = false -ij_javascript_force_semicolon_style = false -ij_javascript_function_expression_brace_style = end_of_line -ij_javascript_if_brace_force = never -ij_javascript_import_merge_members = global -ij_javascript_import_prefer_absolute_path = global -ij_javascript_import_sort_members = true -ij_javascript_import_sort_module_name = false -ij_javascript_import_use_node_resolution = true -ij_javascript_imports_wrap = on_every_item -ij_javascript_indent_case_from_switch = true -ij_javascript_indent_chained_calls = true -ij_javascript_indent_package_children = 0 -ij_javascript_jsx_attribute_value = braces -ij_javascript_keep_blank_lines_in_code = 2 -ij_javascript_keep_first_column_comment = true -ij_javascript_keep_indents_on_empty_lines = false -ij_javascript_keep_line_breaks = true -ij_javascript_keep_simple_blocks_in_one_line = false -ij_javascript_keep_simple_methods_in_one_line = false -ij_javascript_line_comment_add_space = true -ij_javascript_line_comment_at_first_column = false -ij_javascript_method_brace_style = end_of_line -ij_javascript_method_call_chain_wrap = off -ij_javascript_method_parameters_new_line_after_left_paren = false -ij_javascript_method_parameters_right_paren_on_new_line = false -ij_javascript_method_parameters_wrap = off -ij_javascript_object_literal_wrap = on_every_item -ij_javascript_object_types_wrap = on_every_item -ij_javascript_parentheses_expression_new_line_after_left_paren = false -ij_javascript_parentheses_expression_right_paren_on_new_line = false -ij_javascript_place_assignment_sign_on_next_line = false -ij_javascript_prefer_as_type_cast = false -ij_javascript_prefer_explicit_types_function_expression_returns = false -ij_javascript_prefer_explicit_types_function_returns = false -ij_javascript_prefer_explicit_types_vars_fields = false -ij_javascript_prefer_parameters_wrap = false -ij_javascript_reformat_c_style_comments = false -ij_javascript_space_after_colon = true -ij_javascript_space_after_comma = true -ij_javascript_space_after_dots_in_rest_parameter = false -ij_javascript_space_after_generator_mult = true -ij_javascript_space_after_property_colon = true -ij_javascript_space_after_quest = true -ij_javascript_space_after_type_colon = true -ij_javascript_space_after_unary_not = false -ij_javascript_space_before_async_arrow_lparen = true -ij_javascript_space_before_catch_keyword = true -ij_javascript_space_before_catch_left_brace = true -ij_javascript_space_before_catch_parentheses = true -ij_javascript_space_before_class_lbrace = true -ij_javascript_space_before_class_left_brace = true -ij_javascript_space_before_colon = true -ij_javascript_space_before_comma = false -ij_javascript_space_before_do_left_brace = true -ij_javascript_space_before_else_keyword = true -ij_javascript_space_before_else_left_brace = true -ij_javascript_space_before_finally_keyword = true -ij_javascript_space_before_finally_left_brace = true -ij_javascript_space_before_for_left_brace = true -ij_javascript_space_before_for_parentheses = true -ij_javascript_space_before_for_semicolon = false -ij_javascript_space_before_function_left_parenth = true -ij_javascript_space_before_generator_mult = false -ij_javascript_space_before_if_left_brace = true -ij_javascript_space_before_if_parentheses = true -ij_javascript_space_before_method_call_parentheses = false -ij_javascript_space_before_method_left_brace = true -ij_javascript_space_before_method_parentheses = false -ij_javascript_space_before_property_colon = false -ij_javascript_space_before_quest = true -ij_javascript_space_before_switch_left_brace = true -ij_javascript_space_before_switch_parentheses = true -ij_javascript_space_before_try_left_brace = true -ij_javascript_space_before_type_colon = false -ij_javascript_space_before_unary_not = false -ij_javascript_space_before_while_keyword = true -ij_javascript_space_before_while_left_brace = true -ij_javascript_space_before_while_parentheses = true -ij_javascript_spaces_around_additive_operators = true -ij_javascript_spaces_around_arrow_function_operator = true -ij_javascript_spaces_around_assignment_operators = true -ij_javascript_spaces_around_bitwise_operators = true -ij_javascript_spaces_around_equality_operators = true -ij_javascript_spaces_around_logical_operators = true -ij_javascript_spaces_around_multiplicative_operators = true -ij_javascript_spaces_around_relational_operators = true -ij_javascript_spaces_around_shift_operators = true -ij_javascript_spaces_around_unary_operator = false -ij_javascript_spaces_within_array_initializer_brackets = false -ij_javascript_spaces_within_brackets = false -ij_javascript_spaces_within_catch_parentheses = false -ij_javascript_spaces_within_for_parentheses = false -ij_javascript_spaces_within_if_parentheses = false -ij_javascript_spaces_within_imports = false -ij_javascript_spaces_within_interpolation_expressions = false -ij_javascript_spaces_within_method_call_parentheses = false -ij_javascript_spaces_within_method_parentheses = false -ij_javascript_spaces_within_object_literal_braces = false -ij_javascript_spaces_within_object_type_braces = true -ij_javascript_spaces_within_parentheses = false -ij_javascript_spaces_within_switch_parentheses = false -ij_javascript_spaces_within_type_assertion = false -ij_javascript_spaces_within_union_types = true -ij_javascript_spaces_within_while_parentheses = false -ij_javascript_special_else_if_treatment = true -ij_javascript_ternary_operation_signs_on_next_line = false -ij_javascript_ternary_operation_wrap = off -ij_javascript_union_types_wrap = on_every_item -ij_javascript_use_chained_calls_group_indents = false -ij_javascript_use_double_quotes = true -ij_javascript_use_explicit_js_extension = auto -ij_javascript_use_path_mapping = always -ij_javascript_use_public_modifier = false -ij_javascript_use_semicolon_after_statement = true -ij_javascript_var_declaration_wrap = normal -ij_javascript_while_brace_force = never -ij_javascript_while_on_new_line = false -ij_javascript_wrap_comments = false - -[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] -indent_size = 2 -ij_json_array_wrapping = split_into_lines -ij_json_keep_blank_lines_in_code = 0 -ij_json_keep_indents_on_empty_lines = false -ij_json_keep_line_breaks = true -ij_json_keep_trailing_comma = false -ij_json_object_wrapping = split_into_lines -ij_json_property_alignment = do_not_align -ij_json_space_after_colon = true -ij_json_space_after_comma = true -ij_json_space_before_colon = false -ij_json_space_before_comma = false -ij_json_spaces_within_braces = false -ij_json_spaces_within_brackets = false -ij_json_wrap_long_lines = false - -[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] -ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 -ij_html_align_attributes = true -ij_html_align_text = false -ij_html_attribute_wrap = normal -ij_html_block_comment_add_space = false -ij_html_block_comment_at_first_column = true -ij_html_do_not_align_children_of_min_lines = 0 -ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p -ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot -ij_html_enforce_quotes = false -ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var -ij_html_keep_blank_lines = 2 -ij_html_keep_indents_on_empty_lines = false -ij_html_keep_line_breaks = true -ij_html_keep_line_breaks_in_text = true -ij_html_keep_whitespaces = false -ij_html_keep_whitespaces_inside = span, pre, textarea -ij_html_line_comment_at_first_column = true -ij_html_new_line_after_last_attribute = never -ij_html_new_line_before_first_attribute = never -ij_html_quote_style = double -ij_html_remove_new_line_before_tags = br -ij_html_space_after_tag_name = false -ij_html_space_around_equality_in_attribute = false -ij_html_space_inside_empty_tag = false -ij_html_text_wrap = normal - -[{*.markdown,*.md}] -ij_markdown_force_one_space_after_blockquote_symbol = true -ij_markdown_force_one_space_after_header_symbol = true -ij_markdown_force_one_space_after_list_bullet = true -ij_markdown_force_one_space_between_words = true -ij_markdown_format_tables = true -ij_markdown_insert_quote_arrows_on_wrap = true -ij_markdown_keep_indents_on_empty_lines = false -ij_markdown_keep_line_breaks_inside_text_blocks = true -ij_markdown_max_lines_around_block_elements = 1 -ij_markdown_max_lines_around_header = 1 -ij_markdown_max_lines_between_paragraphs = 1 -ij_markdown_min_lines_around_block_elements = 1 -ij_markdown_min_lines_around_header = 1 -ij_markdown_min_lines_between_paragraphs = 1 -ij_markdown_wrap_text_if_long = true -ij_markdown_wrap_text_inside_blockquotes = true diff --git a/next.config.mjs b/next.config.mjs index 4678774..bb49d74 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,8 @@ +const isProd = process.env.NODE_ENV === 'production' + /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + assetPrefix: isProd ? '/v3' : undefined, +}; export default nextConfig; diff --git a/package.json b/package.json index 3e7a01c..4a1bf6b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\"", + "build:publish": "npm i && npm run build && pm2 restart ecosystem.config.js" }, "dependencies": { "@emotion/cache": "^11.11.0", @@ -16,21 +18,27 @@ "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", "@mui/x-date-pickers": "^6.19.5", + "axios": "^1.7.2", "date-fns": "^3.3.1", "date-fns-jalali": "^2.13.0-0", "dayjs": "^1.11.10", "formik": "^2.4.5", "jalali-moment": "^3.3.11", "material-react-table": "^2.11.2", - "next": "14.1.0", + "next": "^14.2.3", "react": "^18", "react-dom": "^18", + "react-toastify": "^10.0.5", "sass": "^1.75.0", "stylis": "^4.3.1", - "stylis-plugin-rtl": "^2.1.1" + "stylis-plugin-rtl": "^2.1.1", + "swr": "^2.2.5", + "yup": "^1.4.0" }, "devDependencies": { "eslint": "^8", - "eslint-config-next": "14.1.0" + "eslint-config-next": "14.1.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.3.2" } -} +} \ No newline at end of file diff --git a/public/global.scss b/public/global.scss index 7802651..1af3ae3 100644 --- a/public/global.scss +++ b/public/global.scss @@ -1 +1,9 @@ -@import "fontiran"; \ No newline at end of file +@import "fontiran"; +@import "react-toastify/dist/ReactToastify.css"; + +.filter-toast { + box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, + rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; + background-color: #d0dfe8; + border: 1px dashed #095b8c; +} diff --git a/public/images/headerLogo.png b/public/images/headerLogo.png new file mode 100644 index 0000000..86dbfcd Binary files /dev/null and b/public/images/headerLogo.png differ diff --git a/public/images/rmsLogo.svg b/public/images/rmsLogo.svg new file mode 100644 index 0000000..5c47991 --- /dev/null +++ b/public/images/rmsLogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/(withAuth)/dashboard/layout.js b/src/app/(withAuth)/dashboard/layout.js deleted file mode 100644 index 877f900..0000000 --- a/src/app/(withAuth)/dashboard/layout.js +++ /dev/null @@ -1,7 +0,0 @@ -const Layout = ({children}) => { - return ( - <>{children} - ) -} - -export default Layout \ No newline at end of file diff --git a/src/app/(withAuth)/dashboard/page.js b/src/app/(withAuth)/dashboard/page.js index f0731fe..a7efa2a 100644 --- a/src/app/(withAuth)/dashboard/page.js +++ b/src/app/(withAuth)/dashboard/page.js @@ -1,7 +1,11 @@ -const Page = () => { - return ( -
dashboard
- ) -} +"use client"; -export default Page \ No newline at end of file +const Page = () => { + + return ( + <> + + ); +}; + +export default Page; diff --git a/src/app/(withAuth)/dashboard/template.js b/src/app/(withAuth)/dashboard/template.js index c44d626..28b4ea0 100644 --- a/src/app/(withAuth)/dashboard/template.js +++ b/src/app/(withAuth)/dashboard/template.js @@ -1,16 +1,17 @@ -import {Box, Stack} from "@mui/material"; +import { Box, Stack } from "@mui/material"; import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo"; import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar"; +import "react-toastify/dist/ReactToastify.css"; -const Template = ({children}) => { - return ( - - - - {children} - - - ) -} +const Template = ({ children }) => { + return ( + + + + {children} + + + ); +}; -export default Template \ No newline at end of file +export default Template; diff --git a/src/app/(withAuth)/layout.js b/src/app/(withAuth)/layout.js new file mode 100644 index 0000000..400bbc9 --- /dev/null +++ b/src/app/(withAuth)/layout.js @@ -0,0 +1,12 @@ +import WithAuthMiddleware from "@/core/middlewares/withAuth"; +import { AuthProvider } from "@/lib/contexts/auth"; + +const Layout = ({ children }) => { + return ( + + {children} + + ); +}; + +export default Layout; diff --git a/src/app/default.js b/src/app/default.js new file mode 100644 index 0000000..d157a71 --- /dev/null +++ b/src/app/default.js @@ -0,0 +1,3 @@ +export default function Default() { + return null; +} diff --git a/src/app/layout.js b/src/app/layout.js index c23a7ec..64aea89 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,17 +1,15 @@ -import {TableSettingProvider} from "@/lib/contexts/tableSetting"; +import { TableSettingProvider } from "@/lib/contexts/tableSetting"; export const metadata = { - title: 'سامانه جامع راهداری', -} + title: "سامانه جامع راهداری", +}; -export default function RootLayout({children}) { +export default function RootLayout({ children }) { return ( - - - - {children} - - + + + {children} + - ) + ); } diff --git a/src/app/lfwd/page.js b/src/app/lfwd/page.js new file mode 100644 index 0000000..b3456a3 --- /dev/null +++ b/src/app/lfwd/page.js @@ -0,0 +1,57 @@ +"use client"; + +import { GET_LOGIN_ROUTE } from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { Button, Stack, Typography, Zoom } from "@mui/material"; +import Link from "next/link"; +import { useEffect, useState } from "react"; + +const Page = ({ searchParams }) => { + const { username } = searchParams; + const [login, setLogin] = useState(0); + const request = useRequest(); + + useEffect(() => { + const login = async () => { + try { + await request(`${GET_LOGIN_ROUTE}?username=${username}`); + setLogin(1); + } catch (error) { + setLogin(2); + } + }; + + login(); + }, []); + + const retry = async () => { + setLogin(0); + try { + await request(`${GET_LOGIN_ROUTE}?username=${username}`); + setLogin(1); + } catch (error) { + setLogin(2); + } + }; + + return ( + + + {login === 0 + ? "درحال دریافت مجوز برای ارتباط با سرور..." + : login === 1 + ? "ارتباط با سرور برقرار شد." + : "ارتباط با سرور برقرار نشد. مشکلی وجود دارد."} + + + + + + + + + ); +}; +export default Page; diff --git a/src/app/page.js b/src/app/page.js index ed41c91..2997c35 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,148 +1,8 @@ -'use client' -import DataTable from "@/core/components/DataTable"; -import { useMemo } from "react"; +import { redirect } from "next/navigation"; function Page() { - const columns = useMemo( - () => [ - { - accessorKey: 'fullname', - header: 'نام کامل', - id: "fullname", - columns: [ - { - accessorKey: 'name.firstName', - header: 'نام', - id: "firstName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - enableClickToCopy: true, - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'name.lastName', - header: 'نام خانوادگی', - id: "lastName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - ], - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'address', - header: 'آدرس', - id: "address", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'city', - header: 'شهر', - id: "city", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains", - "lessThan", - "greaterThan", - "between", - ], - - }, - { - accessorKey: 'state', - header: 'وضعیت', - id: "state", - text: 'نام', - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'state', - header: 'محدوده', - id: "betweenNum", - text: 'محدوده', - enableColumnFilter: true, - datatype: "text", - filterFn: "betweenNum", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'تاریخ', - id: "betweenDate", - text: 'تاریخ', - enableColumnFilter: true, - datatype: "text", - filterFn: "betweenDate", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'شلکت', - id: "select2", - text: 'تاریخ', - type: 'select2', - enableColumnFilter: true, - datatype: "text", - filterFn: "equals", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'سلکت', - id: "select", - text: 'تنتنت', - type: 'select', - enableColumnFilter: true, - datatype: "text", - filterFn: "equals", - columnFilterModeOptions: [], - }, - ], - [], - ); - - return ( - <> - - - - ); + redirect("/dashboard", "replace"); + return null; } export default Page; diff --git a/src/app/template.js b/src/app/template.js index cc8a8f2..3ffc656 100644 --- a/src/app/template.js +++ b/src/app/template.js @@ -1,18 +1,21 @@ import cacheProviderRtl from "@/core/utils/cacheRtl"; -import {CssBaseline, ThemeProvider} from "@mui/material"; +import { CssBaseline, ThemeProvider } from "@mui/material"; import theme from "@/core/utils/theme"; -import {AppRouterCacheProvider} from "@mui/material-nextjs/v14-appRouter"; -import "^/global.scss" +import { AppRouterCacheProvider } from "@mui/material-nextjs/v14-appRouter"; +import "^/global.scss"; +import { ToastContainer } from "react-toastify"; -const Template = ({children}) => { +const Template = ({ children }) => { return ( - + - + {children} + + - ) -} + ); +}; -export default Template \ No newline at end of file +export default Template; diff --git a/src/components/BetweenDateFilter.jsx b/src/components/BetweenDateFilter.jsx deleted file mode 100644 index e8e8c18..0000000 --- a/src/components/BetweenDateFilter.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import {Grid} from '@mui/material'; -import MuiDatePicker from "@/components/MuiDatePicker"; -import {useEffect, useState} from "react"; - -const BetWeenDateFilter = ({formik, id , defaultValue}) => { - useEffect(() => { - formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || ''); - formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || ''); - }, []); - - const [dateRange, setDateRange] = useState(defaultValue); - - const handleDateChange = (index, value) => { - const newRange = [...dateRange]; - newRange[index] = value; - setDateRange(newRange); - }; - - return ( - - - handleDateChange(0, value)}/> - - - handleDateChange(1, value)}/> - - - ); -}; - -export default BetWeenDateFilter; diff --git a/src/components/BetweenNumberFilter.jsx b/src/components/BetweenNumberFilter.jsx deleted file mode 100644 index 0b3512a..0000000 --- a/src/components/BetweenNumberFilter.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import {Grid, TextField} from '@mui/material'; -import {useEffect} from "react"; - -const BetweenNumberFilter = ({formik, id , defaultValue}) => { - - useEffect(() => { - formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || ''); - formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || ''); - }, []); - const handleBlur = (index) => () => { - const minValue = formik.values[id][0]; - const maxValue = formik.values[id][1]; - - if (index === 0 && minValue !== '' && maxValue !== '' && parseInt(minValue) > parseInt(maxValue)) { - formik.setFieldValue(`${id}[0]`, maxValue); - } - - if (index === 1 && minValue !== '' && maxValue !== '' && parseInt(maxValue) < parseInt(minValue)) { - formik.setFieldValue(`${id}[1]`, minValue); - } - }; - return ( - - - - - - - - - ); -}; - -export default BetweenNumberFilter; diff --git a/src/components/CustomToolbar.jsx b/src/components/CustomToolbar.jsx deleted file mode 100644 index 344b5da..0000000 --- a/src/components/CustomToolbar.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import FilterColumn from "@/components/FilterColumn"; - -const CustomToolbar = ({columns}) => { - return ( - - ) -} -export default CustomToolbar - - - - - - - - - - - - diff --git a/src/components/DataTableMain.jsx b/src/components/DataTableMain.jsx deleted file mode 100644 index a6e8c91..0000000 --- a/src/components/DataTableMain.jsx +++ /dev/null @@ -1,141 +0,0 @@ -import DataTableTest from "@/components/DataTableTest"; -import FilterColumn from "@/components/FilterColumn"; -import {useMemo} from "react"; -import {Button} from "@mui/material"; - -function DataTableMain() { - const columns = useMemo( - () => [ - { - accessorKey: 'name.firstName', - header: 'نام', - size: 150, - id: "firstName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'name.lastName', - header: 'نام خانوادگی', - size: 150, - id: "lastName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'address', - header: 'آدرس', - size: 200, - id: "address", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'city', - header: 'شهر', - size: 150, - id: "city", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains", - "lessThan", - "greaterThan", - "between", - ], - - }, - { - accessorKey: 'state', - header: 'وضعیت', - size: 150, - id: "state", - text:'نام', - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'state', - header: 'محدوده', - size: 150, - id: "betweenNum", - text:'محدوده', - enableColumnFilter: true, - datatype: "text", - filterFn: "betweenNum", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'تاریخ', - size: 150, - id: "betweenDate", - text:'تاریخ', - enableColumnFilter: true, - datatype: "text", - filterFn: "betweenDate", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'شلکت', - size: 150, - id: "select2", - text:'تاریخ', - type: 'select2', - enableColumnFilter: true, - datatype: "text", - filterFn: "equals", - columnFilterModeOptions: [], - }, - { - accessorKey: 'state', - header: 'سلکت', - size: 150, - id: "select", - text:'تنتنت', - type: 'select', - enableColumnFilter: true, - datatype: "text", - filterFn: "equals", - columnFilterModeOptions: [], - }, - ], - [], - ); - return ( - <> - - - - ); -} - -export default DataTableMain; diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx deleted file mode 100644 index bf610fb..0000000 --- a/src/components/DataTableTest.jsx +++ /dev/null @@ -1,104 +0,0 @@ -"use client" -import {useMemo, useState} from 'react'; -import {MaterialReactTable} from 'material-react-table'; -import useTableSetting from "@/lib/hooks/useTableSetting"; -import {IconButton, Tooltip, Typography} from "@mui/material"; -import CustomToolbar from "@/components/CustomToolbar"; - - -const data = [ - { - name: { - firstName: 'John', - lastName: 'Doe', - }, - address: '261 Erdman Ford', - city: 'East Daphne', - state: 'Kentucky', - }, - { - name: { - firstName: 'Jane', - lastName: 'Doe', - }, - address: '769 Dominic Grove', - city: 'Columbus', - state: 'Ohio', - }, - { - name: { - firstName: 'Joe', - lastName: 'Doe', - }, - address: '566 Brakus Inlet', - city: 'South Linda', - state: 'West Virginia', - }, - { - name: { - firstName: 'Kevin', - lastName: 'Vandy', - }, - address: '722 Emie Stream', - city: 'Lincoln', - state: 'Nebraska', - }, - { - name: { - firstName: 'Joshua', - lastName: 'Rolluffs', - }, - address: '32188 Larkin Turnpike', - city: 'Charleston', - state: 'South Carolina', - }, -]; - -function RefreshIcon() { - return null; -} - -const TestDataTable = ({columns}) => { - const [userId, setUserId] = useState(2); - const [pageName, setPageName] = useState('loan'); - const [tableName, setTableName] = useState('loan_table'); - const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); - - const onColumnVisibilityChange = (event) => { - const settingValue = event(); - hideAction(userId, pageName, tableName, settingValue, columns); - }; - const onSortingChange = (event) => { - const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); - sortAction(userId, pageName, tableName, settingValue, columns); - } - - return ( - <> - {settingStore?.[userId]?.[pageName]?.[tableName]?.['summary']} - (<> - - )} - initialState={{ - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [] - }} - state={{ - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [] - }} - onColumnVisibilityChange={onColumnVisibilityChange} - onSortingChange={onSortingChange} - /> - - ); -}; - -export default TestDataTable; - diff --git a/src/components/FilterBox.jsx b/src/components/FilterBox.jsx deleted file mode 100644 index f887918..0000000 --- a/src/components/FilterBox.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Popper, Paper, List, ListItem, ListItemText, ClickAwayListener } from '@mui/material'; - -function FilterBox({anchorEl , open = false, handleClose = () => {} , columnFilterModeOptions , onSelectFilter , defaultFilter}) { - - const id = open ? 'simple-popper' : undefined; - const handleSelectFilter = (filterFn) => { - onSelectFilter(filterFn); - handleClose(); - }; - - return ( -
- - - - - {columnFilterModeOptions.map((option, index) => ( - handleSelectFilter(option)} selected={option === defaultFilter} sx={{ cursor: 'pointer' }}> - - - ))} - - - - -
- ); -} - -export default FilterBox; diff --git a/src/components/FilterColumn.jsx b/src/components/FilterColumn.jsx deleted file mode 100644 index 08e42c0..0000000 --- a/src/components/FilterColumn.jsx +++ /dev/null @@ -1,204 +0,0 @@ -"use client" -import { - Box, - Button, Divider, Drawer, - FormControl, IconButton, styled, Typography -} from '@mui/material'; -import {useFormik} from 'formik'; -import TextFieldWithFnBox from "@/components/TextFieldWithFnBox"; -import {useEffect, useState} from "react"; -import useTableSetting from "@/lib/hooks/useTableSetting"; -import BetweenNumberFilter from "@/components/BetweenNumberFilter"; -import BetWeenDateFilter from "@/components/BetweenDateFilter"; -import SelectBoxMultiple from "@/components/SelectBoxMultiple"; -import SelectBox from "@/components/SelectBox"; -import CloseIcon from '@mui/icons-material/Close'; -import { useTheme } from '@mui/material/styles'; - -function FilterColumn({ columns }) { - const [open, setOpen] = useState(false); - const [selectedFilters, setSelectedFilters] = useState([]); - const [userId, setUserId] = useState(2); - const [pageName, setPageName] = useState('loan'); - const [tableName, setTableName] = useState('loan_table'); - const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); - - const DrawerHeader = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - padding: theme.spacing(0, 1), - justifyContent: 'space-between', - })); - const toggleDrawer = (newOpen) => () => { - setOpen(newOpen); - }; - const handleDrawerClose = () => { - setOpen(false); - }; - useEffect(() => { - const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []; - setSelectedFilters(settingValue.length > 0 ? settingValue : []); - }, [settingStore]); - - const handleSelectFilter = (fieldName, filterFn) => { - const filterIndex = selectedFilters.findIndex(filter => filter.id === fieldName); - - if (filterIndex !== -1) { - const updatedFilters = [...selectedFilters]; - updatedFilters[filterIndex].fn = filterFn; - setSelectedFilters(updatedFilters); - } else { - const newFilter = { id: fieldName, fn: filterFn }; - const updatedFilters = [...selectedFilters, newFilter]; - setSelectedFilters(updatedFilters); - } - }; - - const initialValues = columns.reduce((acc, column) => { - if (column.enableColumnFilter) { - const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id); - if (column.filterFn === 'betweenNum' || column.filterFn === 'betweenDate') { - acc[column.id] = filter?.value || ["", ""]; - } - else if ( column.type === 'select2' ) { - acc[column.id] = filter?.value || []; - } - else { - acc[column.id] = filter?.value || ''; - } - } - return acc; - }, {}); - - const formik = useFormik({ - initialValues, - onSubmit: (values) => { - const updatedFilters = selectedFilters.map(filter => { - const value = values[filter.id]; - if (value !== undefined) { - return { ...filter, value }; - } - return filter; - }); - Object.entries(values).forEach(([fieldName, value]) => { - const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName); - if (filterIndex === -1 && value !== '' && value !== null && value !== undefined) { - const column = columns.find(col => col.id === fieldName); - updatedFilters.push({ id: fieldName, value, fn: column.filterFn, datatype: column.datatype }); - } - }); - - const newArrayFilter = updatedFilters.filter((filter) => { - const value = values[filter.id]; - - return ( - value !== '' && - value !== null && - value !== undefined && - !(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value.every((v) => v === '')))) - ); - }); - - setSelectedFilters(newArrayFilter); - filterAction(userId, pageName, tableName, newArrayFilter, columns); - } - - }); - - return ( - <> - - - - فیلتر - - - - - - - {columns.map((column, index) => ( - column.enableColumnFilter && - (column.filterFn === 'betweenDate' ? - handleSelectFilter(column.id, filterFn)} - defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''} - /> - : column.filterFn === 'betweenNum' ? - handleSelectFilter(column.id, filterFn)} - defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ["", ""]} - /> - : column.type === 'select2' ? - handleSelectFilter(column.id, filterFn)} - defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || []} - /> - : column.type === 'select' ? - handleSelectFilter(column.id, filterFn)} - defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''} - /> - : - filter.id === column.id)?.fn || column.filterFn} - columnFilterModeOptions={column.columnFilterModeOptions} - onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)} - defaultValue={formik.values[column.id] || (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''} - /> - ) - ))} - - - - - - - - - - - ); -} - -export default FilterColumn; - - diff --git a/src/components/MapTest.jsx b/src/components/MapTest.jsx deleted file mode 100644 index 8ccea0a..0000000 --- a/src/components/MapTest.jsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client" -import {Typography} from "@mui/material"; - -const data = [ - { - id : "hello", - Subitems : [ - {id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false}, - {id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - }, - { - id : "hi", - Subitems : [ - {id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false}, - {id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - } -] -const MapTest = () => { - const Amin = data.map((item) => { - return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => true ? { - ...subitem, showSubitems: !item.showSubitems - } : subitem)} : item - }) - - - console.log(Amin) - - - return ( - <> - hello - - ) -} -export default MapTest \ No newline at end of file diff --git a/src/components/SelectBox.jsx b/src/components/SelectBox.jsx deleted file mode 100644 index 88cce6e..0000000 --- a/src/components/SelectBox.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import InputLabel from '@mui/material/InputLabel'; -import MenuItem from '@mui/material/MenuItem'; -import FormControl from '@mui/material/FormControl'; -import Select from '@mui/material/Select'; -import {useEffect, useState} from "react"; -const names = [ - 'Oliver Hansen', - 'Van Henry', - 'April Tucker', - 'Ralph Hubbard', - 'Omar Alexander', - 'Carlos Abbott', - 'Miriam Wagner', - 'Bradley Wilkerson', - 'Virginia Andrews', - 'Kelly Snyder', -]; -const SelectBox = ({ formik, id, defaultValue }) => { - - useEffect(() => { - formik.setFieldValue(id, defaultValue || ''); - }, []); - - const [selectedValue, setSelectedValue] = useState(defaultValue || ''); - - const handleChange = (event) => { - const { value } = event.target; - setSelectedValue(value); - formik.setFieldValue(id, value); - }; - - return ( - <> - - انتخاب - - - - ); -}; - -export default SelectBox; diff --git a/src/components/SelectBoxMultiple.jsx b/src/components/SelectBoxMultiple.jsx deleted file mode 100644 index 4355c72..0000000 --- a/src/components/SelectBoxMultiple.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import {useTheme} from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import OutlinedInput from '@mui/material/OutlinedInput'; -import InputLabel from '@mui/material/InputLabel'; -import MenuItem from '@mui/material/MenuItem'; -import FormControl from '@mui/material/FormControl'; -import Select from '@mui/material/Select'; -import Chip from '@mui/material/Chip'; -import {useEffect, useState} from "react"; - -const ITEM_HEIGHT = 48; -const ITEM_PADDING_TOP = 8; -const MenuProps = { - PaperProps: { - style: { - maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, - width: 250, - }, - }, -}; - -const names = [ - 'Oliver Hansen', - 'Van Henry', - 'April Tucker', - 'Ralph Hubbard', - 'Omar Alexander', - 'Carlos Abbott', - 'Miriam Wagner', - 'Bradley Wilkerson', - 'Virginia Andrews', - 'Kelly Snyder', -]; - -function getStyles(name, personName, theme) { - return { - fontWeight: - personName.indexOf(name) === -1 - ? theme.typography.fontWeightRegular - : theme.typography.fontWeightMedium, - }; -} - -const SelectBoxMultiple = ({formik, id, defaultValue}) => { - const theme = useTheme(); - const [personName, setPersonName] = useState(defaultValue || []); - - useEffect(() => { - defaultValue.forEach((value, index) => { - formik.setFieldValue(`${id}[${index}]`, value || ''); - }); - - }, []); - - const handleChange = (event) => { - const { - target: {value}, - } = event; - - const selectedValues = typeof value === 'string' ? value.split(',').filter(item => item.trim() !== '') : value; - - formik.setFieldValue(id, []); - - if (selectedValues.length === 0) { - setPersonName([]); - formik.setFieldValue(id, []); - } else { - setPersonName(selectedValues); - selectedValues.forEach((selectedValue, index) => { - formik.setFieldValue(`${id}[${index}]`, selectedValue); - }); - } - }; - - return ( - <> - - انتخاب - - - - ); -}; - -export default SelectBoxMultiple; diff --git a/src/components/TextFieldWithFnBox.jsx b/src/components/TextFieldWithFnBox.jsx deleted file mode 100644 index 6ba443b..0000000 --- a/src/components/TextFieldWithFnBox.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import {IconButton, Paper, TextField} from '@mui/material'; -import ArtTrackIcon from '@mui/icons-material/ArtTrack'; -import {useEffect, useState} from "react"; -import FilterBox from "@/components/FilterBox"; - -const TextFieldWithFnBox = ({formik, id , header, defaultValue, defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { - - const [anchorEl, setAnchorEl] = useState(null); - const [open, setOpen] = useState(false); - - useEffect(() => { - formik.setFieldValue(id, defaultValue || ''); - }, []); - - const handleClick = (event) => { - setOpen((prevOpen) => !prevOpen); - setAnchorEl(anchorEl ? null : event.currentTarget); - }; - - const handleClose = () => { - setOpen(false); - setAnchorEl(null); - }; - - return ( - <> - - - - ) - }} - sx={{ - position: 'relative' - }} - /> - - - ); -}; - -export default TextFieldWithFnBox; diff --git a/src/components/home/Toolbar.jsx b/src/components/home/Toolbar.jsx new file mode 100644 index 0000000..82f2646 --- /dev/null +++ b/src/components/home/Toolbar.jsx @@ -0,0 +1,10 @@ +import { Button } from "@mui/material"; + +const Toolbar = ({ columns }) => { + return ( + <> + + + ); +}; +export default Toolbar; diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx new file mode 100644 index 0000000..7344232 --- /dev/null +++ b/src/components/home/index.jsx @@ -0,0 +1,129 @@ +"use client"; +import DataTable from "@/core/components/DataTable"; +import { useMemo } from "react"; + +function HomeComponent() { + const columns = useMemo( + () => [ + { + accessorKey: "fullname", + header: "نام کامل", + id: "fullname", + columns: [ + { + accessorKey: "name.firstName", + header: "نام", + id: "firstName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + enableClickToCopy: true, + columnFilterModeOptions: ["equals", "notEquals", "contains"], + }, + { + accessorKey: "name.lastName", + header: "نام خانوادگی", + id: "lastName", + enableColumnFilter: true, + datatype: "text", + filterFn: "equals", + columnFilterModeOptions: ["equals", "notEquals", "contains"], + }, + ], + }, + { + accessorKey: "address", + header: "آدرس", + id: "address", + enableColumnFilter: true, + datatype: "text", + filterFn: "notEquals", + columnFilterModeOptions: ["equals", "notEquals", "contains"], + }, + { + accessorKey: "city", + header: "شهر", + id: "city", + enableColumnFilter: true, + datatype: "text", + filterFn: "equals", + columnFilterModeOptions: ["equals", "notEquals", "contains", "lessThan", "greaterThan", "fuzzy"], + }, + { + accessorKey: "state", + header: "وضعیت", + id: "state", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["equals", "notEquals", "contains"], + }, + { + accessorKey: "price", + header: "محدوده", + id: "price", + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: ["equals", "notEquals"], + }, + { + accessorKey: "created_at", + header: "تاریخ ساخت", + id: "created_at", + enableColumnFilter: true, + datatype: "date", + filterFn: "between", + }, + { + accessorKey: "updated_at", + header: "تاریخ بروزرسانی", + id: "updated_at", + enableColumnFilter: true, + datatype: "date", + filterFn: "equals", + }, + { + accessorKey: "company", + header: "نام شرکت", + id: "company", + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnSelectOption: [ + { value: 1, label: "وایتل" }, + { value: 2, label: "اسنپ" }, + { value: 3, label: "تپسی" }, + ], + }, + { + accessorKey: "area", + header: "منطقه", + id: "area", + enableColumnFilter: true, + datatype: "array", + filterFn: "equals", + columnSelectOption: [ + { value: 1, label: "وایتل" }, + { value: 2, label: "اسنپ" }, + { value: 3, label: "تپسی" }, + ], + }, + ], + [] + ); + + return ( + <> + + + ); +} + +export default HomeComponent; diff --git a/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx b/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx new file mode 100644 index 0000000..62ec234 --- /dev/null +++ b/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx @@ -0,0 +1,27 @@ +"use client"; +import { Stack, Typography } from "@mui/material"; +import Image from "next/image"; + +const HeaderBottom = () => { + return ( + theme.palette.primary2.main, + }} + spacing={4} + alignItems={"center"} + direction={"row"} + > + + + theme.palette.primary2.contrastText }}> + سامانه جامع راهداری + + theme.palette.primary2.contrastText }}>rms.rmto.ir + + + ); +}; +export default HeaderBottom; diff --git a/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx b/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx new file mode 100644 index 0000000..6899881 --- /dev/null +++ b/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx @@ -0,0 +1,11 @@ +import { Stack } from "@mui/material"; +import Image from "next/image"; + +const HeaderTop = () => { + return ( + + + + ); +}; +export default HeaderTop; diff --git a/src/components/layouts/dashboard/headerWithLogo/index.jsx b/src/components/layouts/dashboard/headerWithLogo/index.jsx index f16f58c..16ef4b2 100644 --- a/src/components/layouts/dashboard/headerWithLogo/index.jsx +++ b/src/components/layouts/dashboard/headerWithLogo/index.jsx @@ -1,9 +1,13 @@ -import {Box, Stack} from "@mui/material"; +import { Box, Stack } from "@mui/material"; +import HeaderTop from "./HaederTop"; +import HeaderBottom from "./HaederBottom"; const HeaderWithLogo = () => { - return ( - header1 - header2 - ) -} -export default HeaderWithLogo \ No newline at end of file + return ( + + + + + ); +}; +export default HeaderWithLogo; diff --git a/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx new file mode 100644 index 0000000..c705242 --- /dev/null +++ b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx @@ -0,0 +1,4 @@ +const HeaderMenu = () => { + return <>منو; +}; +export default HeaderMenu; diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx index eeb88a3..c8febb6 100644 --- a/src/components/layouts/dashboard/headerWithSidebar/index.jsx +++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx @@ -1,94 +1,110 @@ -'use client' -import {useState} from "react"; -import {Box, Drawer, IconButton, Paper, styled, Toolbar, Typography} from "@mui/material"; -import MuiAppBar from '@mui/material/AppBar'; -import MenuIcon from '@mui/icons-material/Menu'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +"use client"; import SidebarMenu from "@/core/components/SidebarMenu"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import MenuIcon from "@mui/icons-material/Menu"; +import { Box, Drawer, IconButton, Paper, styled, Toolbar } from "@mui/material"; +import MuiAppBar from "@mui/material/AppBar"; +import { useState } from "react"; +import HeaderMenu from "./HeaderMenu"; -const drawerWidth = 260; +const drawerWidth = 300; -const Main = styled(Paper, {shouldForwardProp: (prop) => prop !== 'open'})(({theme, open}) => ({ - flexGrow: 1, transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, - }), marginLeft: `-${drawerWidth}px`, ...(open && { - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.easeOut, duration: theme.transitions.duration.enteringScreen, - }), marginLeft: 0, +const Main = styled(Paper, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({ + flexGrow: 1, + transition: theme.transitions.create("margin", { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, }), -}),); + marginLeft: `-${drawerWidth}px`, + ...(open && { + transition: theme.transitions.create("margin", { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + marginLeft: 0, + }), +})); const AppBar = styled(MuiAppBar, { - shouldForwardProp: (prop) => prop !== 'open', -})(({theme, open}) => ({ - transition: theme.transitions.create(['margin', 'width'], { - easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, - }), ...(open && { + shouldForwardProp: (prop) => prop !== "open", +})(({ theme, open }) => ({ + transition: theme.transitions.create(["margin", "width"], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + ...(open && { width: `calc(100% - ${drawerWidth}px)`, marginLeft: `${drawerWidth}px`, - transition: theme.transitions.create(['margin', 'width'], { - easing: theme.transitions.easing.easeOut, duration: theme.transitions.duration.enteringScreen, + transition: theme.transitions.create(["margin", "width"], { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, }), }), })); -const DrawerHeader = styled('div')(({theme}) => ({ - display: 'flex', alignItems: 'center', padding: theme.spacing(0, 1), // necessary for content to be below app bar - ...theme.mixins.toolbar, justifyContent: 'flex-end', +const DrawerHeader = styled("div")(({ theme }) => ({ + display: "flex", + alignItems: "center", + padding: theme.spacing(0, 1), + ...theme.mixins.toolbar, + justifyContent: "flex-end", })); -const HeaderWithSidebar = ({children}) => { - const [open, setOpen] = useState(false); +const HeaderWithSidebar = ({ children }) => { + const [open, setOpen] = useState(true); const handleDrawerOpen = () => { setOpen(true); }; - const handleDrawerClose = () => { setOpen(false); }; - return ( - - - - - - - menu - - - - + + + + + + + + + + + - - - - - - - -
- - {children} -
-
) -} -export default HeaderWithSidebar \ No newline at end of file + flexShrink: 0, + "& .MuiDrawer-paper": { + width: drawerWidth, + boxSizing: "border-box", + borderTop: 1, + borderTopColor: "divider", + top: "unset", + }, + }} + variant="persistent" + anchor="left" + open={open} + > + + + + + + + +
+ + {children} +
+ + ); +}; +export default HeaderWithSidebar; diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js index 4a38956..db8aebd 100644 --- a/src/core/components/DataTable/Main.js +++ b/src/core/components/DataTable/Main.js @@ -1,19 +1,183 @@ -import { useMaterialReactTable } from "material-react-table"; import DataTable_Paper from "./table/Paper"; +import { useMaterialReactTable } from "material-react-table"; +import { FA_DATATABLE_LOCALIZATION } from "./localization/fa/datatable"; +import useTableSetting from "@/lib/hooks/useTableSetting"; +import { flattenArrayOfObjects } from "@/core/utils/flattenArrayOfObjects"; +import Toolbar from "@/components/home/Toolbar"; +import useDataTable from "@/lib/hooks/useDataTable"; +import { useMemo, useState } from "react"; -const isTableInstanceProp = (props) => props.table !== undefined; +const data = [ + { + name: { + firstName: "امین", + lastName: "قاسمپور", + }, + address: "فلان جا", + city: "تهران", + state: "بررسی شده", + price: "20", + updated_at: "2024/05/02", + company: "همراه اول", + area: "منطقه 5", + }, + { + name: { + firstName: "امیر حسین", + lastName: "محمودی", + }, + address: "فلان جا", + city: "تهران", + state: "تکمیل شده", + price: "27", + updated_at: "2024/05/02", + company: "وایتل", + area: "منطقه 27", + }, + { + name: { + firstName: "یاسمن", + lastName: "علی اکبری", + }, + address: "فلان جا", + city: "شیراز", + state: "بررسی شده", + price: "32", + updated_at: "2024/05/02", + company: "ایرانسل", + area: "منطقه 23", + }, + { + name: { + firstName: "حمیدرضا", + lastName: "رنجبرپور", + }, + address: "فلان جا", + city: "اصفهان", + state: "بررسی شده", + price: "45", + updated_at: "2024/05/02", + company: "ایرانول", + area: "منطقه 21", + }, + { + name: { + firstName: "محمد", + lastName: "جلالی", + }, + address: "فلان جا", + city: "رشت", + state: "درحال بررسی", + price: "8", + updated_at: "2024/05/02", + company: "فیلیمو", + area: "منطقه 8", + }, +]; const DataTable_Main = (props) => { - let table; + const { filterData } = useDataTable(); + const { table_url, user_id, page_name, table_name, columns, initialStateProps } = props; + const flatColumns = flattenArrayOfObjects(columns, "columns"); + const { settingStore, hideAction, sortAction } = useTableSetting(); + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); + const filters = Object.keys(filterData) + .map((key) => { + const value = filterData[key].value; + if ( + value !== "" && + !( + Array.isArray(value) && + (value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === "")) + ) + ) { + return filterData[key]; + } + }) + .filter(Boolean); + const storedFilters = settingStore?.[user_id]?.[page_name]?.[table_name]?.filters; + const finalFilters = storedFilters || filters; - if (isTableInstanceProp(props)) { - table = props.table; - } else { - // eslint-disable-next-line react-hooks/rules-of-hooks - table = useMaterialReactTable(props); - } + const fetchUrl = useMemo(() => { + const params = new URLSearchParams(); + params.set("start", `${pagination.pageIndex * pagination.pageSize}`); + params.set("size", pagination.pageSize); + params.set("filters", JSON.stringify(finalFilters ?? [])); + params.set("sorting", JSON.stringify(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] ?? [])); + return `${table_url}?${params}`; + }, [table_url, finalFilters, pagination, columns]); - return ; + const onColumnVisibilityChange = (event) => { + const settingValue = event(); + hideAction(user_id, page_name, table_name, settingValue, flatColumns); + }; + const onSortingChange = (event) => { + const settingValue = event(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []); + sortAction(user_id, page_name, table_name, settingValue, flatColumns); + }; + + const table = useMaterialReactTable({ + localization: FA_DATATABLE_LOCALIZATION, + columns, + data: data, + // manualSorting: true, + renderTopToolbarCustomActions: ({ table }) => ( + <> + + + ), + initialState: { + density: "compact", + columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"], + sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || [], + ...initialStateProps, + }, + state: { + columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"], + sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || [], + pagination, + }, + muiTableHeadProps: { + sx: { + borderTop: "1px solid #e1e1e1", + borderBottom: "2px solid #e1e1e1", + }, + }, + muiTableHeadCellProps: { + sx: { + color: "primary.main", + borderLeft: "1px solid #e1e1e1", + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + manualFiltering: true, + manualPagination: true, + onPaginationChange: setPagination, + manualSorting: true, + onColumnVisibilityChange: onColumnVisibilityChange, + onSortingChange: onSortingChange, + ...props, + }); + + return ( + + ); }; export default DataTable_Main; diff --git a/src/core/components/DataTable/body/TableBody.js b/src/core/components/DataTable/body/TableBody.js index e1620a3..b0750be 100644 --- a/src/core/components/DataTable/body/TableBody.js +++ b/src/core/components/DataTable/body/TableBody.js @@ -4,11 +4,7 @@ import { useMRT_RowVirtualizer, useMRT_Rows } from "material-react-table"; import { memo, useMemo } from "react"; import DataTable_TableBodyRow, { Memo_DataTable_TableBodyRow } from "./TableBodyRow"; -const DataTable_TableBody = ({ - columnVirtualizer, - table, - ...rest -}) => { +const DataTable_TableBody = ({ columnVirtualizer, table, ...rest }) => { const { getBottomRows, getIsSomeRowsPinned, @@ -35,12 +31,8 @@ const DataTable_TableBody = ({ ...rest, }; - const tableHeadHeight = - ((enableStickyHeader || isFullScreen) && - tableHeadRef.current?.clientHeight) || - 0; - const tableFooterHeight = - (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0; + const tableHeadHeight = ((enableStickyHeader || isFullScreen) && tableHeadRef.current?.clientHeight) || 0; + const tableFooterHeight = (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0; const pinnedRowIds = useMemo(() => { if (!rowPinning.bottom?.length && !rowPinning.top?.length) return []; @@ -63,67 +55,63 @@ const DataTable_TableBody = ({ return ( <> - {!rowPinningDisplayMode?.includes('sticky') && - getIsSomeRowsPinned('top') && ( - ({ - display: layoutMode?.startsWith('grid') ? 'grid' : undefined, - position: 'sticky', - top: tableHeadHeight - 1, - zIndex: 1, - ...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)), - })} - > - {getTopRows().map((row, staticRowIndex) => { - const props = { - ...commonRowProps, - row, - staticRowIndex, - }; - return memoMode === 'rows' ? ( - - ) : ( - - ); - })} - - )} + {!rowPinningDisplayMode?.includes("sticky") && getIsSomeRowsPinned("top") && ( + ({ + display: layoutMode?.startsWith("grid") ? "grid" : undefined, + position: "sticky", + top: tableHeadHeight - 1, + zIndex: 1, + ...parseFromValuesOrFunc(tableBodyProps?.sx, theme), + })} + > + {getTopRows().map((row, staticRowIndex) => { + const props = { + ...commonRowProps, + row, + staticRowIndex, + }; + return memoMode === "rows" ? ( + + ) : ( + + ); + })} + + )} ({ - display: layoutMode?.startsWith('grid') ? 'grid' : undefined, - height: rowVirtualizer - ? `${rowVirtualizer.getTotalSize()}px` - : undefined, - minHeight: !rows.length ? '100px' : undefined, - position: 'relative', - ...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)), + display: layoutMode?.startsWith("grid") ? "grid" : undefined, + height: rowVirtualizer ? `${rowVirtualizer.getTotalSize()}px` : undefined, + minHeight: !rows.length ? "100px" : undefined, + position: "relative", + ...parseFromValuesOrFunc(tableBodyProps?.sx, theme), })} > {tableBodyProps?.children ?? (!rows.length ? ( {renderEmptyRowsFallback?.({ table }) ?? ( {globalFilter || columnFilters.length @@ -155,12 +143,10 @@ const DataTable_TableBody = ({ row, rowVirtualizer, staticRowIndex, - virtualRow: rowVirtualizer - ? (rowOrVirtualRow) - : undefined, + virtualRow: rowVirtualizer ? rowOrVirtualRow : undefined, }; const key = `${row.id}-${row.index}`; - return memoMode === 'rows' ? ( + return memoMode === "rows" ? ( ) : ( @@ -169,39 +155,37 @@ const DataTable_TableBody = ({ ))} - {!rowPinningDisplayMode?.includes('sticky') && - getIsSomeRowsPinned('bottom') && ( - ({ - bottom: tableFooterHeight - 1, - display: layoutMode?.startsWith('grid') ? 'grid' : undefined, - position: 'sticky', - zIndex: 1, - ...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)), - })} - > - {getBottomRows().map((row, staticRowIndex) => { - const props = { - ...commonRowProps, - row, - staticRowIndex, - }; - return memoMode === 'rows' ? ( - - ) : ( - - ); - })} - - )} + {!rowPinningDisplayMode?.includes("sticky") && getIsSomeRowsPinned("bottom") && ( + ({ + bottom: tableFooterHeight - 1, + display: layoutMode?.startsWith("grid") ? "grid" : undefined, + position: "sticky", + zIndex: 1, + ...parseFromValuesOrFunc(tableBodyProps?.sx, theme), + })} + > + {getBottomRows().map((row, staticRowIndex) => { + const props = { + ...commonRowProps, + row, + staticRowIndex, + }; + return memoMode === "rows" ? ( + + ) : ( + + ); + })} + + )} ); - -} -export default DataTable_TableBody +}; +export default DataTable_TableBody; export const Memo_DataTable_TableBody = memo( DataTable_TableBody, - (prev, next) => prev.table.options.data === next.table.options.data, -); \ No newline at end of file + (prev, next) => prev.table.options.data === next.table.options.data +); diff --git a/src/core/components/DataTable/body/TableBodyCell.js b/src/core/components/DataTable/body/TableBodyCell.js index 9ef022d..4c1804b 100644 --- a/src/core/components/DataTable/body/TableBodyCell.js +++ b/src/core/components/DataTable/body/TableBodyCell.js @@ -7,15 +7,7 @@ const { useState, useEffect, useMemo, memo } = require("react"); const { default: DataTable_CopyButton } = require("../buttons/CopyButton"); const { default: DataTable_TableBodyCellValue } = require("./TableBodyCellValue"); -const DataTable_TableBodyCell = ({ - cell, - numRows, - rowRef, - staticColumnIndex, - staticRowIndex, - table, - ...rest -}) => { +const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, staticRowIndex, table, ...rest }) => { const theme = useTheme(); const { getState, @@ -73,9 +65,7 @@ const DataTable_TableBodyCell = ({ if ((!isLoading && !showSkeletons) || skeletonWidth !== 100) return; const size = column.getSize(); setSkeletonWidth( - columnDefType === 'display' - ? size / 2 - : Math.round(Math.random() * (size - size / 3) + size / 3), + columnDefType === "display" ? size / 2 : Math.round(Math.random() * (size - size / 3) + size / 3) ); }, [isLoading, showSkeletons]); @@ -88,77 +78,55 @@ const DataTable_TableBodyCell = ({ const isLastColumn = column.getIsLastColumn(); const isLastRow = numRows && staticRowIndex === numRows - 1; const isResizingColumn = columnSizingInfo.isResizingColumn === column.id; - const showResizeBorder = - isResizingColumn && columnResizeMode === 'onChange'; + const showResizeBorder = isResizingColumn && columnResizeMode === "onChange"; const borderStyle = showResizeBorder ? `2px solid ${draggingBorderColor} !important` : isDraggingColumn || isDraggingRow - ? `1px dashed ${theme.palette.grey[500]} !important` - : isHoveredColumn || isHoveredRow || isResizingColumn - ? `2px dashed ${draggingBorderColor} !important` - : undefined; + ? `1px dashed ${theme.palette.grey[500]} !important` + : isHoveredColumn || isHoveredRow || isResizingColumn + ? `2px dashed ${draggingBorderColor} !important` + : undefined; if (showResizeBorder) { - return columnResizeDirection === 'ltr' - ? { borderRight: borderStyle } - : { borderLeft: borderStyle }; + return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle }; } return borderStyle ? { - borderBottom: - isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn) - ? borderStyle - : undefined, - borderLeft: - isDraggingColumn || - isHoveredColumn || - ((isDraggingRow || isHoveredRow) && isFirstColumn) - ? borderStyle - : undefined, - borderRight: - isDraggingColumn || - isHoveredColumn || - ((isDraggingRow || isHoveredRow) && isLastColumn) - ? borderStyle - : undefined, - borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined, - } + borderBottom: + isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn) ? borderStyle : undefined, + borderLeft: + isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isFirstColumn) + ? borderStyle + : undefined, + borderRight: + isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isLastColumn) + ? borderStyle + : undefined, + borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined, + } : undefined; - }, [ - columnSizingInfo.isResizingColumn, - draggingColumn, - draggingRow, - hoveredColumn, - hoveredRow, - staticRowIndex, - ]); + }, [columnSizingInfo.isResizingColumn, draggingColumn, draggingRow, hoveredColumn, hoveredRow, staticRowIndex]); - const isColumnPinned = - enableColumnPinning && - columnDef.columnDefType !== 'group' && - column.getIsPinned(); + const isColumnPinned = enableColumnPinning && columnDef.columnDefType !== "group" && column.getIsPinned(); const isEditable = isCellEditable({ cell, table }); const isEditing = isEditable && - !['custom', 'modal'].includes(editDisplayMode) && - (editDisplayMode === 'table' || - editingRow?.id === row.id || - editingCell?.id === cell.id) && + !["custom", "modal"].includes(editDisplayMode) && + (editDisplayMode === "table" || editingRow?.id === row.id || editingCell?.id === cell.id) && !row.getIsGrouped(); - const isCreating = - isEditable && createDisplayMode === 'row' && creatingRow?.id === row.id; + const isCreating = isEditable && createDisplayMode === "row" && creatingRow?.id === row.id; const showClickToCopyButton = (parseFromValuesOrFunc(enableClickToCopy, cell) === true || parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === true) && - !['context-menu', false].includes( + !["context-menu", false].includes( // @ts-ignore - parseFromValuesOrFunc(columnDef.enableClickToCopy, cell), + parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) ); const isRightClickable = parseFromValuesOrFunc(enableCellActions, cell); @@ -175,13 +143,11 @@ const DataTable_TableBodyCell = ({ const handleDragEnter = (e) => { tableCellProps?.onDragEnter?.(e); - if (enableGrouping && hoveredColumn?.id === 'drop-zone') { + if (enableGrouping && hoveredColumn?.id === "drop-zone") { setHoveredColumn(null); } if (enableColumnOrdering && draggingColumn) { - setHoveredColumn( - columnDef.enableColumnOrdering !== false ? column : null, - ); + setHoveredColumn(columnDef.enableColumnOrdering !== false ? column : null); } }; @@ -210,43 +176,39 @@ const DataTable_TableBodyCell = ({ onDragEnter={handleDragEnter} onDragOver={handleDragOver} sx={(theme) => ({ - '&:hover': { + "&:hover": { outline: actionCell?.id === cell.id || - (editDisplayMode === 'cell' && isEditable) || - (editDisplayMode === 'table' && (isCreating || isEditing)) + (editDisplayMode === "cell" && isEditable) || + (editDisplayMode === "table" && (isCreating || isEditing)) ? `1px solid ${theme.palette.grey[500]}` : undefined, - textOverflow: 'clip', + textOverflow: "clip", }, - alignItems: layoutMode?.startsWith('grid') ? 'center' : undefined, + alignItems: layoutMode?.startsWith("grid") ? "center" : undefined, cursor: isRightClickable - ? 'context-menu' - : isEditable && editDisplayMode === 'cell' - ? 'pointer' - : 'inherit', - outline: - actionCell?.id === cell.id - ? `1px solid ${theme.palette.grey[500]}` - : undefined, - outlineOffset: '-1px', - overflow: 'hidden', + ? "context-menu" + : isEditable && editDisplayMode === "cell" + ? "pointer" + : "inherit", + outline: actionCell?.id === cell.id ? `1px solid ${theme.palette.grey[500]}` : undefined, + outlineOffset: "-1px", + overflow: "hidden", p: - density === 'compact' - ? columnDefType === 'display' - ? '0 0.5rem' - : '0.5rem' - : density === 'comfortable' - ? columnDefType === 'display' - ? '0.5rem 0.75rem' - : '1rem' - : columnDefType === 'display' - ? '1rem 1.25rem' - : '1.5rem', + density === "compact" + ? columnDefType === "display" + ? "0 0.5rem" + : "0.5rem" + : density === "comfortable" + ? columnDefType === "display" + ? "0.5rem 0.75rem" + : "1rem" + : columnDefType === "display" + ? "1rem 1.25rem" + : "1.5rem", - textOverflow: columnDefType !== 'display' ? 'ellipsis' : undefined, - whiteSpace: - row.getIsPinned() || density === 'compact' ? 'nowrap' : 'normal', + textOverflow: columnDefType !== "display" ? "ellipsis" : undefined, + whiteSpace: row.getIsPinned() || density === "compact" ? "nowrap" : "normal", ...getCommonMRTCellStyles({ column, table, @@ -261,17 +223,10 @@ const DataTable_TableBodyCell = ({ {cell.getIsPlaceholder() ? ( columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null ) : showSkeletons !== false && (isLoading || showSkeletons) ? ( - - ) : columnDefType === 'display' && - (['mrt-row-expand', 'mrt-row-numbers', 'mrt-row-select'].includes( - column.id, - ) || - !row.getIsGrouped()) ? ( + + ) : columnDefType === "display" && + (["mrt-row-expand", "mrt-row-numbers", "mrt-row-select"].includes(column.id) || + !row.getIsGrouped()) ? ( columnDef.Cell?.({ cell, column, @@ -289,18 +244,12 @@ const DataTable_TableBodyCell = ({ ) : ( )} - {cell.getIsGrouped() && !columnDef.GroupedCell && ( - <> ({row.subRows?.length}) - )} + {cell.getIsGrouped() && !columnDef.GroupedCell && <> ({row.subRows?.length})} )} ); - -} +}; export default DataTable_TableBodyCell; -export const Memo_DataTable_TableBodyCell = memo( - DataTable_TableBodyCell, - (prev, next) => next.cell === prev.cell, -); \ No newline at end of file +export const Memo_DataTable_TableBodyCell = memo(DataTable_TableBodyCell, (prev, next) => next.cell === prev.cell); diff --git a/src/core/components/DataTable/body/TableBodyCellValue.js b/src/core/components/DataTable/body/TableBodyCellValue.js index 6d4f05f..aea105f 100644 --- a/src/core/components/DataTable/body/TableBodyCellValue.js +++ b/src/core/components/DataTable/body/TableBodyCellValue.js @@ -2,111 +2,102 @@ import { Box } from "@mui/material"; const allowedTypes = ["string", "number"]; -const DataTable_TableBodyCellValue = ({ - cell, - rowRef, - staticColumnIndex, - staticRowIndex, - table, -}) => { - const { - getState, - options: { - enableFilterMatchHighlighting, - mrtTheme: { matchHighlightColor }, - }, - } = table; - const { column, row } = cell; - const { columnDef } = column; - const { globalFilter, globalFilterFn } = getState(); - const filterValue = column.getFilterValue(); +const DataTable_TableBodyCellValue = ({ cell, rowRef, staticColumnIndex, staticRowIndex, table }) => { + const { + getState, + options: { + enableFilterMatchHighlighting, + mrtTheme: { matchHighlightColor }, + }, + } = table; + const { column, row } = cell; + const { columnDef } = column; + const { globalFilter, globalFilterFn } = getState(); + const filterValue = column.getFilterValue(); - let renderedCellValue = - cell.getIsAggregated() && columnDef.AggregatedCell - ? columnDef.AggregatedCell({ - cell, - column, - row, - table, - }) - : row.getIsGrouped() && !cell.getIsGrouped() - ? null - : cell.getIsGrouped() && columnDef.GroupedCell - ? columnDef.GroupedCell({ + let renderedCellValue = + cell.getIsAggregated() && columnDef.AggregatedCell + ? columnDef.AggregatedCell({ + cell, + column, + row, + table, + }) + : row.getIsGrouped() && !cell.getIsGrouped() + ? null + : cell.getIsGrouped() && columnDef.GroupedCell + ? columnDef.GroupedCell({ + cell, + column, + row, + table, + }) + : undefined; + + const isGroupedValue = renderedCellValue !== undefined; + + if (!isGroupedValue) { + renderedCellValue = cell.renderValue(); + } + + if ( + enableFilterMatchHighlighting && + columnDef.enableFilterMatchHighlighting !== false && + String(renderedCellValue) && + allowedTypes.includes(typeof renderedCellValue) && + ((filterValue && + allowedTypes.includes(typeof filterValue) && + ["autocomplete", "text"].includes(columnDef.filterVariant)) || + (globalFilter && allowedTypes.includes(typeof globalFilter) && column.getCanGlobalFilter())) + ) { + const chunks = highlightWords?.({ + matchExactly: (filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy", + query: (filterValue ?? globalFilter ?? "").toString(), + text: renderedCellValue?.toString(), + }); + if (chunks?.length > 1 || chunks?.[0]?.match) { + renderedCellValue = ( + + {chunks?.map(({ key, match, text }) => ( + + )) ?? renderedCellValue} + + ); + } + } + + if (columnDef.Cell && !isGroupedValue) { + renderedCellValue = columnDef.Cell({ cell, column, + renderedCellValue, row, + rowRef, + staticColumnIndex, + staticRowIndex, table, - }) - : undefined; - - const isGroupedValue = renderedCellValue !== undefined; - - if (!isGroupedValue) { - renderedCellValue = cell.renderValue(); - } - - if ( - enableFilterMatchHighlighting && - columnDef.enableFilterMatchHighlighting !== false && - String(renderedCellValue) && - allowedTypes.includes(typeof renderedCellValue) && - ((filterValue && - allowedTypes.includes(typeof filterValue) && - ["autocomplete", "text"].includes(columnDef.filterVariant)) || - (globalFilter && - allowedTypes.includes(typeof globalFilter) && - column.getCanGlobalFilter())) - ) { - const chunks = highlightWords?.({ - matchExactly: - (filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy", - query: (filterValue ?? globalFilter ?? "").toString(), - text: renderedCellValue?.toString(), - }); - if (chunks?.length > 1 || chunks?.[0]?.match) { - renderedCellValue = ( - - {chunks?.map(({ key, match, text }) => ( - - )) ?? renderedCellValue} - - ); + }); } - } - if (columnDef.Cell && !isGroupedValue) { - renderedCellValue = columnDef.Cell({ - cell, - column, - renderedCellValue, - row, - rowRef, - staticColumnIndex, - staticRowIndex, - table, - }); - } - - return renderedCellValue; + return renderedCellValue; }; export default DataTable_TableBodyCellValue; diff --git a/src/core/components/DataTable/body/TableBodyRow.js b/src/core/components/DataTable/body/TableBodyRow.js index e500eb0..a041d66 100644 --- a/src/core/components/DataTable/body/TableBodyRow.js +++ b/src/core/components/DataTable/body/TableBodyRow.js @@ -28,11 +28,7 @@ const DataTable_TableBodyRow = ({ enableStickyHeader, layoutMode, memoMode, - mrtTheme: { - baseBackgroundColor, - pinnedRowBackgroundColor, - selectedRowBackgroundColor, - }, + mrtTheme: { baseBackgroundColor, pinnedRowBackgroundColor, selectedRowBackgroundColor }, muiTableBodyRowProps, renderDetailPanel, rowPinningDisplayMode, @@ -40,21 +36,12 @@ const DataTable_TableBodyRow = ({ refs: { tableFooterRef, tableHeadRef }, setHoveredRow, } = table; - const { - density, - draggingColumn, - draggingRow, - editingCell, - editingRow, - hoveredRow, - isFullScreen, - rowPinning, - } = getState(); + const { density, draggingColumn, draggingRow, editingCell, editingRow, hoveredRow, isFullScreen, rowPinning } = + getState(); const visibleCells = row.getVisibleCells(); - const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = - columnVirtualizer ?? {}; + const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = columnVirtualizer ?? {}; const isRowSelected = getIsRowSelected({ row, table }); const isRowPinned = enableRowPinning && row.getIsPinned(); @@ -71,30 +58,17 @@ const DataTable_TableBodyRow = ({ }; const [bottomPinnedIndex, topPinnedIndex] = useMemo(() => { - if ( - !enableRowPinning || - !rowPinningDisplayMode?.includes('sticky') || - !pinnedRowIds || - !row.getIsPinned() - ) + if (!enableRowPinning || !rowPinningDisplayMode?.includes("sticky") || !pinnedRowIds || !row.getIsPinned()) return []; - return [ - [...pinnedRowIds].reverse().indexOf(row.id), - pinnedRowIds.indexOf(row.id), - ]; + return [[...pinnedRowIds].reverse().indexOf(row.id), pinnedRowIds.indexOf(row.id)]; }, [pinnedRowIds, rowPinning]); - const tableHeadHeight = - ((enableStickyHeader || isFullScreen) && - tableHeadRef.current?.clientHeight) || - 0; - const tableFooterHeight = - (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0; + const tableHeadHeight = ((enableStickyHeader || isFullScreen) && tableHeadRef.current?.clientHeight) || 0; + const tableFooterHeight = (enableStickyFooter && tableFooterRef.current?.clientHeight) || 0; const sx = parseFromValuesOrFunc(tableRowProps?.sx, theme); - const defaultRowHeight = - density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69; + const defaultRowHeight = density === "compact" ? 37 : density === "comfortable" ? 53 : 69; const customRowHeight = // @ts-ignore @@ -117,16 +91,16 @@ const DataTable_TableBodyRow = ({ const cellHighlightColor = isRowSelected ? selectedRowBackgroundColor : isRowPinned - ? pinnedRowBackgroundColor - : undefined; + ? pinnedRowBackgroundColor + : undefined; const cellHighlightColorHover = tableRowProps?.hover !== false ? isRowSelected ? cellHighlightColor - : theme.palette.mode === 'dark' - ? `${lighten(baseBackgroundColor, 0.3)}` - : `${darken(baseBackgroundColor, 0.3)}` + : theme.palette.mode === "dark" + ? `${lighten(baseBackgroundColor, 0.3)}` + : `${darken(baseBackgroundColor, 0.3)}` : undefined; return ( @@ -146,91 +120,81 @@ const DataTable_TableBodyRow = ({ selected={isRowSelected} {...tableRowProps} style={{ - transform: virtualRow - ? `translateY(${virtualRow.start}px)` - : undefined, + transform: virtualRow ? `translateY(${virtualRow.start}px)` : undefined, ...tableRowProps?.style, }} sx={(theme) => ({ - '&:hover td:after': cellHighlightColorHover + "&:hover td:after": cellHighlightColorHover ? { - backgroundColor: alpha(cellHighlightColorHover, 0.3), - ...commonCellBeforeAfterStyles, - } + backgroundColor: alpha(cellHighlightColorHover, 0.3), + ...commonCellBeforeAfterStyles, + } : undefined, backgroundColor: `${baseBackgroundColor} !important`, bottom: !virtualRow && bottomPinnedIndex !== undefined && isRowPinned - ? `${bottomPinnedIndex * rowHeight + - (enableStickyFooter ? tableFooterHeight - 1 : 0) - }px` + ? `${bottomPinnedIndex * rowHeight + (enableStickyFooter ? tableFooterHeight - 1 : 0)}px` : undefined, - boxSizing: 'border-box', - display: layoutMode?.startsWith('grid') ? 'flex' : undefined, + boxSizing: "border-box", + display: layoutMode?.startsWith("grid") ? "flex" : undefined, opacity: isRowPinned ? 0.97 : isDraggingRow || isHoveredRow ? 0.5 : 1, position: virtualRow - ? 'absolute' - : rowPinningDisplayMode?.includes('sticky') && isRowPinned - ? 'sticky' - : 'relative', + ? "absolute" + : rowPinningDisplayMode?.includes("sticky") && isRowPinned + ? "sticky" + : "relative", td: { ...getCommonPinnedCellStyles({ table, theme }), }, - 'td:after': cellHighlightColor + "td:after": cellHighlightColor ? { - backgroundColor: cellHighlightColor, - ...commonCellBeforeAfterStyles, - } + backgroundColor: cellHighlightColor, + ...commonCellBeforeAfterStyles, + } : undefined, top: virtualRow ? 0 : topPinnedIndex !== undefined && isRowPinned - ? `${topPinnedIndex * rowHeight + - (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0) + ? `${ + topPinnedIndex * rowHeight + + (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0) }px` - : undefined, - transition: virtualRow ? 'none' : 'all 150ms ease-in-out', - width: '100%', - zIndex: - rowPinningDisplayMode?.includes('sticky') && isRowPinned ? 2 : 0, - ...(sx), + : undefined, + transition: virtualRow ? "none" : "all 150ms ease-in-out", + width: "100%", + zIndex: rowPinningDisplayMode?.includes("sticky") && isRowPinned ? 2 : 0, + ...sx, })} > - {virtualPaddingLeft ? ( - - ) : null} - {(virtualColumns ?? visibleCells).map( - (cellOrVirtualCell, staticColumnIndex) => { - let cell = cellOrVirtualCell; - if (columnVirtualizer) { - staticColumnIndex = (cellOrVirtualCell).index; - cell = visibleCells[staticColumnIndex]; - } - const props = { - cell, - numRows, - rowRef, - staticColumnIndex, - staticRowIndex, - table, - }; - return cell ? ( - memoMode === 'cells' && - cell.column.columnDef.columnDefType === 'data' && - !draggingColumn && - !draggingRow && - editingCell?.id !== cell.id && - editingRow?.id !== row.id ? ( - - ) : ( - - ) - ) : null; - }, - )} - {virtualPaddingRight ? ( - - ) : null} + {virtualPaddingLeft ? : null} + {(virtualColumns ?? visibleCells).map((cellOrVirtualCell, staticColumnIndex) => { + let cell = cellOrVirtualCell; + if (columnVirtualizer) { + staticColumnIndex = cellOrVirtualCell.index; + cell = visibleCells[staticColumnIndex]; + } + const props = { + cell, + numRows, + rowRef, + staticColumnIndex, + staticRowIndex, + table, + }; + return cell ? ( + memoMode === "cells" && + cell.column.columnDef.columnDefType === "data" && + !draggingColumn && + !draggingRow && + editingCell?.id !== cell.id && + editingRow?.id !== row.id ? ( + + ) : ( + + ) + ) : null; + })} + {virtualPaddingRight ? : null} {renderDetailPanel && !row.getIsGrouped() && ( ); -} -export default DataTable_TableBodyRow +}; +export default DataTable_TableBodyRow; export const Memo_DataTable_TableBodyRow = memo( DataTable_TableBodyRow, - (prev, next) => - prev.row === next.row && prev.staticRowIndex === next.staticRowIndex, -); \ No newline at end of file + (prev, next) => prev.row === next.row && prev.staticRowIndex === next.staticRowIndex +); diff --git a/src/core/components/DataTable/body/TableDetailPanel.js b/src/core/components/DataTable/body/TableDetailPanel.js index 0c9f8a9..853aab5 100644 --- a/src/core/components/DataTable/body/TableDetailPanel.js +++ b/src/core/components/DataTable/body/TableDetailPanel.js @@ -23,7 +23,6 @@ const DataTable_TableDetailPanel = ({ } = table; const { isLoading } = getState(); - const tableRowProps = parseFromValuesOrFunc(muiTableBodyRowProps, { isDetailPanel: true, row, @@ -52,16 +51,12 @@ const DataTable_TableDetailPanel = ({ }} {...tableRowProps} sx={(theme) => ({ - display: layoutMode?.startsWith('grid') ? 'flex' : undefined, - position: virtualRow ? 'absolute' : undefined, - top: virtualRow - ? `${parentRowRef.current?.getBoundingClientRect()?.height}px` - : undefined, - transform: virtualRow - ? `translateY(${virtualRow?.start}px)` - : undefined, - width: '100%', - ...(parseFromValuesOrFunc(tableRowProps?.sx, theme)), + display: layoutMode?.startsWith("grid") ? "flex" : undefined, + position: virtualRow ? "absolute" : undefined, + top: virtualRow ? `${parentRowRef.current?.getBoundingClientRect()?.height}px` : undefined, + transform: virtualRow ? `translateY(${virtualRow?.start}px)` : undefined, + width: "100%", + ...parseFromValuesOrFunc(tableRowProps?.sx, theme), })} > ({ backgroundColor: virtualRow ? baseBackgroundColor : undefined, - borderBottom: !row.getIsExpanded() ? 'none' : undefined, - display: layoutMode?.startsWith('grid') ? 'flex' : undefined, - py: !!DetailPanel && row.getIsExpanded() ? '1rem' : 0, - transition: !virtualRow ? 'all 150ms ease-in-out' : undefined, + borderBottom: !row.getIsExpanded() ? "none" : undefined, + display: layoutMode?.startsWith("grid") ? "flex" : undefined, + py: !!DetailPanel && row.getIsExpanded() ? "1rem" : 0, + transition: !virtualRow ? "all 150ms ease-in-out" : undefined, width: `100%`, - ...(parseFromValuesOrFunc(tableCellProps?.sx, theme)), + ...parseFromValuesOrFunc(tableCellProps?.sx, theme), })} > {virtualRow ? ( @@ -88,6 +83,5 @@ const DataTable_TableDetailPanel = ({ ); - -} -export default DataTable_TableDetailPanel \ No newline at end of file +}; +export default DataTable_TableDetailPanel; diff --git a/src/core/components/DataTable/buttons/CopyButton.js b/src/core/components/DataTable/buttons/CopyButton.js index c8878e0..c4dfe4b 100644 --- a/src/core/components/DataTable/buttons/CopyButton.js +++ b/src/core/components/DataTable/buttons/CopyButton.js @@ -2,11 +2,7 @@ import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils import { Button, Tooltip } from "@mui/material"; import { useState } from "react"; -const DataTable_CopyButton = ({ - cell, - table, - ...rest -}) => { +const DataTable_CopyButton = ({ cell, table, ...rest }) => { const { options: { localization, muiCopyButtonProps }, } = table; @@ -40,11 +36,8 @@ const DataTable_CopyButton = ({ return ( + + + )} + + + )} + + ); +} + +export default FilterBody; diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx new file mode 100644 index 0000000..a9bef12 --- /dev/null +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -0,0 +1,113 @@ +import { useState } from "react"; +import FilterOptionList from "@/core/components/DataTable/filter/FilterOptionList"; +import CustomSelect from "@/core/components/DataTable/filter/fieldsType/CustomSelect"; +import CustomTextField from "@/core/components/DataTable/filter/fieldsType/CustomTextField"; +import CustomTextFieldRange from "@/core/components/DataTable/filter/fieldsType/CustomTextFieldRange"; +import CustomDatePickerRange from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange"; +import CustomDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker"; +import CustomSelectMultiple from "@/core/components/DataTable/filter/fieldsType/CustomSelectMultiple"; + +const columnFilterModeOptionFa = { + equals: "برابر", + notEquals: "نابرابر", + contains: "شامل", + lessThan: "کوچکتر", + greaterThan: "بزرگتر", + fuzzy: "فازی", + between: "مابین", +}; + +function FilterBodyField({ + column, + filterParameters, + handleChange, + handleBlur, + setFieldValue, + errors, + touched, + resetForm, +}) { + const [anchorEl, setAnchorEl] = useState(null); + const defaultFilterTranslation = columnFilterModeOptionFa[filterParameters.filterFn] || filterParameters.filterFn; + + const handleOpenFilterBox = (event) => { + setAnchorEl(event.currentTarget); + }; + + return ( + <> + {filterParameters.datatype === "numeric" && filterParameters.filterFn === "between" ? ( + + ) : filterParameters.datatype === "numeric" && + filterParameters.filterFn === "equals" && + Array.isArray(column.columnSelectOption) ? ( + + ) : filterParameters.datatype === "date" && filterParameters.filterFn === "equals" ? ( + + ) : filterParameters.datatype === "date" && filterParameters.filterFn === "between" ? ( + + ) : filterParameters.datatype === "array" && filterParameters.filterFn === "equals" ? ( + + ) : ( + setFieldValue(`${column.id}.value`, e.target.value)} + /> + )} + {Array.isArray(column.columnFilterModeOptions) && ( + + )} + + ); +} + +export default FilterBodyField; diff --git a/src/core/components/DataTable/filter/FilterButton.jsx b/src/core/components/DataTable/filter/FilterButton.jsx new file mode 100644 index 0000000..2d22501 --- /dev/null +++ b/src/core/components/DataTable/filter/FilterButton.jsx @@ -0,0 +1,20 @@ +"use client"; +import FilterAltIcon from "@mui/icons-material/FilterAlt"; +import { IconButton, Tooltip } from "@mui/material"; + +function FilterButton({ drawerState, setDrawerState }) { + return ( + + { + setDrawerState(!drawerState); + }} + aria-label="filter table" + > + + + + ); +} + +export default FilterButton; diff --git a/src/core/components/DataTable/filter/FilterHeader.jsx b/src/core/components/DataTable/filter/FilterHeader.jsx new file mode 100644 index 0000000..76980ce --- /dev/null +++ b/src/core/components/DataTable/filter/FilterHeader.jsx @@ -0,0 +1,34 @@ +"use client"; + +import { Box, IconButton, Typography } from "@mui/material"; +import CancelIcon from "@mui/icons-material/Cancel"; +import FilterAltIcon from "@mui/icons-material/FilterAlt"; + +function FilterHeader({ setDrawerState }) { + return ( + + + + + فیلتر + + + setDrawerState(false)}> + + + + ); +} + +export default FilterHeader; diff --git a/src/core/components/DataTable/filter/FilterOptionList.jsx b/src/core/components/DataTable/filter/FilterOptionList.jsx new file mode 100644 index 0000000..e088832 --- /dev/null +++ b/src/core/components/DataTable/filter/FilterOptionList.jsx @@ -0,0 +1,49 @@ +"use client"; + +import { ListItem, Menu } from "@mui/material"; +import { useState } from "react"; + +function FilterOptionList({ + column, + filterType, + filterOption, + anchorEl, + columnFilterModeOptionFa, + setAnchorEl, + setFieldValue, +}) { + const [selectedFilter, setSelectedFilter] = useState(filterType); + + const handleChangeItem = (event, index) => { + setFieldValue(`${column.id}.value`, filterOption[index] === "between" ? ["", ""] : ""); + setFieldValue(`${column.id}.filterFn`, filterOption[index]); + setSelectedFilter(filterOption[index]); + setAnchorEl(null); + }; + + const handleCloseFilterBox = () => { + setAnchorEl(null); + }; + + return ( + + {filterOption.map((option, index) => ( + handleChangeItem(event, index)} + selected={option === selectedFilter} + sx={{ + cursor: "pointer", + width: "100px", + display: "flex", + justifyContent: "center", + }} + > + {columnFilterModeOptionFa[option]} + + ))} + + ); +} + +export default FilterOptionList; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx new file mode 100644 index 0000000..fe5d2e0 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx @@ -0,0 +1,21 @@ +import React from "react"; +import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker"; +import { Typography } from "@mui/material"; + +function CustomDatePicker({ column, filterParameters, defaultFilterTranslation, setFieldValue }) { + return ( + + نوع فیلتر: {defaultFilterTranslation} (تاریخ) + + } + /> + ); +} + +export default CustomDatePicker; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx new file mode 100644 index 0000000..116af77 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx @@ -0,0 +1,35 @@ +"use client"; + +import React from "react"; +import { Box, Typography } from "@mui/material"; +import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker"; + +function CustomDatePickerRange({ column, filterParameters, defaultFilterTranslation, setFieldValue, errors, touched }) { + return ( + + + نوع فیلتر: {defaultFilterTranslation} (تاریخ) + + } + /> + + + ); +} + +export default CustomDatePickerRange; diff --git a/src/components/MuiDatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker.jsx similarity index 52% rename from src/components/MuiDatePicker.jsx rename to src/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker.jsx index f2b0876..b4da7f5 100644 --- a/src/components/MuiDatePicker.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker.jsx @@ -1,38 +1,36 @@ -import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers"; +import React from "react"; +import { LocalizationProvider, MobileDatePicker } from "@mui/x-date-pickers"; import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali"; -import moment from "jalali-moment"; import { faIR } from "@mui/x-date-pickers/locales"; -import { Box, IconButton, InputAdornment, TextField } from "@mui/material"; +import { Box, FormHelperText, IconButton, InputAdornment } from "@mui/material"; import ClearIcon from "@mui/icons-material/Clear"; -import { useState } from "react"; +import moment from "jalali-moment"; -export default function MuiDatePicker({label, name, formik, defaultValue, minDate, maxDate, onDateChange }) { - const [pickerValue, setPickerValue] = useState(defaultValue ? new Date(defaultValue) : null); +function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error }) { return ( - + - { - const date = new Date(newValue); - const formattedDate = moment(date) - .locale("en") - .format("YYYY-MM-DD HH:mm"); - formik.setFieldValue(name, formattedDate); - onDateChange(formattedDate); - setPickerValue(newValue); + { + const date = new Date(value); + const formattedDate = moment(date).locale("en").format("YYYY-MM-DD"); + setFieldValue(name, formattedDate); }} + minDate={minDate ? new Date(minDate) : null} + maxDate={maxDate ? new Date(maxDate) : null} slotProps={{ textField: { - placeholder: "تاریخ خود را وارد کنید", - helperText: label, + error: error, + placeholder: placeholder, InputProps: { endAdornment: ( @@ -40,13 +38,13 @@ export default function MuiDatePicker({label, name, formik, defaultValue, minDat size="small" onClick={(event) => { event.stopPropagation(); - formik.setFieldValue(name, ""); - setPickerValue(null); + setFieldValue(name, ""); }} sx={{ color: "#bfbfbf", - '&:hover': { - backgroundColor: 'rgba(189, 189, 189, 0.1)', + "&:hover": { + backgroundColor: "rgba(189, 189, 189, 0.1)", + color: "#363434", }, }} > @@ -57,11 +55,13 @@ export default function MuiDatePicker({label, name, formik, defaultValue, minDat }, }, }} - value={pickerValue} - minDate={minDate ? new Date(minDate) : null} - maxDate={maxDate ? new Date(maxDate) : null} /> + + {helperText ? helperText : ""} + ); } + +export default MuiDatePicker; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx new file mode 100644 index 0000000..bd038e2 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx @@ -0,0 +1,37 @@ +"use client"; + +import { FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography } from "@mui/material"; + +function CustomSelect({ column, filterParameters, defaultFilterTranslation, setFieldValue }) { + const columnSelectOption = column.columnSelectOption; + + return ( + + {column.header} + + + + نوع فیلتر: {defaultFilterTranslation} + + + + ); +} + +export default CustomSelect; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx new file mode 100644 index 0000000..130f98f --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx @@ -0,0 +1,60 @@ +"use client"; + +import { + Box, + Chip, + FormControl, + FormHelperText, + InputLabel, + MenuItem, + OutlinedInput, + Select, + Typography, +} from "@mui/material"; + +function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslation, setFieldValue }) { + const columnSelectOption = column.columnSelectOption; + + const getLabelForValue = (value) => { + const option = columnSelectOption.find((opt) => opt.value === value); + return option ? option.label : value; + }; + + return ( + + + {column.header} + + + + + نوع فیلتر: {defaultFilterTranslation} + + + + ); +} + +export default CustomSelectMultiple; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx new file mode 100644 index 0000000..05b44ce --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx @@ -0,0 +1,40 @@ +import { InputAdornment, TextField, Typography } from "@mui/material"; +import FilterListIcon from "@mui/icons-material/FilterList"; + +function CustomTextField({ + column, + filterParameters, + defaultFilterTranslation, + handleOpenFilterBox, + handleChange, + handleBlur, +}) { + return ( + + نوع فیلتر: {defaultFilterTranslation} + + } + variant="outlined" + size="normal" + sx={{ marginY: 1 }} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + ); +} + +export default CustomTextField; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx new file mode 100644 index 0000000..fea4169 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx @@ -0,0 +1,59 @@ +import { Box, InputAdornment, TextField, Typography } from "@mui/material"; +import FilterListIcon from "@mui/icons-material/FilterList"; + +function CustomTextFieldRange({ + column, + filterParameters, + defaultFilterTranslation, + handleOpenFilterBox, + handleChange, + handleBlur, + errors, + touched, +}) { + return ( + + از {column.header}} + value={filterParameters.value[0]} + fullWidth + error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)} + helperText={ + + نوع فیلتر: {defaultFilterTranslation} + + } + variant="outlined" + size="normal" + sx={{ marginY: 1, marginRight: 1 }} + /> + تا {column.header}} + value={filterParameters.value[1]} + fullWidth + variant="outlined" + size="normal" + sx={{ marginY: 1 }} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + + ); +} + +export default CustomTextFieldRange; diff --git a/src/core/components/DataTable/filter/index.jsx b/src/core/components/DataTable/filter/index.jsx new file mode 100644 index 0000000..8d26594 --- /dev/null +++ b/src/core/components/DataTable/filter/index.jsx @@ -0,0 +1,25 @@ +"use client"; + +import { useState } from "react"; +import FilterButton from "@/core/components/DataTable/filter/FilterButton"; +import FilterBody from "@/core/components/DataTable/filter/FilterBody"; + +function FilterColumn({ columns, user_id, page_name, table_name }) { + const [open, setOpen] = useState(false); + + return ( + <> + + + + ); +} + +export default FilterColumn; diff --git a/src/core/components/DataTable/head/TableHead.js b/src/core/components/DataTable/head/TableHead.js index 055a4ed..39ee214 100644 --- a/src/core/components/DataTable/head/TableHead.js +++ b/src/core/components/DataTable/head/TableHead.js @@ -2,19 +2,10 @@ import { parseFromValuesOrFunc } from "@/core/utils/utils"; import { TableHead } from "@mui/material"; import DataTable_TableHeadRow from "./TableHeadRow"; -const DataTable_TableHead = ({ - columnVirtualizer, - table, - ...rest -}) => { +const DataTable_TableHead = ({ columnVirtualizer, table, ...rest }) => { const { getState, - options: { - enableStickyHeader, - layoutMode, - muiTableHeadProps, - positionToolbarAlertBanner, - }, + options: { enableStickyHeader, layoutMode, muiTableHeadProps, positionToolbarAlertBanner }, refs: { tableHeadRef }, } = table; const { isFullScreen, showAlertBanner } = getState(); @@ -37,27 +28,24 @@ const DataTable_TableHead = ({ } }} sx={(theme) => ({ - display: layoutMode?.startsWith('grid') ? 'grid' : undefined, + display: layoutMode?.startsWith("grid") ? "grid" : undefined, opacity: 0.97, - position: stickyHeader ? 'sticky' : 'relative', - top: stickyHeader && layoutMode?.startsWith('grid') ? 0 : undefined, + position: stickyHeader ? "sticky" : "relative", + top: stickyHeader && layoutMode?.startsWith("grid") ? 0 : undefined, zIndex: stickyHeader ? 2 : undefined, - ...(parseFromValuesOrFunc(tableHeadProps?.sx, theme)), + ...parseFromValuesOrFunc(tableHeadProps?.sx, theme), })} > - {table - .getHeaderGroups() - .map((headerGroup) => ( - - )) - } + {table.getHeaderGroups().map((headerGroup, index) => ( + + ))} ); - -} -export default DataTable_TableHead \ No newline at end of file +}; +export default DataTable_TableHead; diff --git a/src/core/components/DataTable/head/TableHeadCell.js b/src/core/components/DataTable/head/TableHeadCell.js index 78a9933..a0b8fc5 100644 --- a/src/core/components/DataTable/head/TableHeadCell.js +++ b/src/core/components/DataTable/head/TableHeadCell.js @@ -4,13 +4,7 @@ import { Box, TableCell } from "@mui/material"; import { MRT_TableHeadCellSortLabel } from "material-react-table"; import { useMemo } from "react"; -const DataTable_TableHeadCell = ({ - columnVirtualizer, - header, - staticColumnIndex, - table, - ...rest -}) => { +const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex, table, ...rest }) => { const theme = useTheme(); const { getState, @@ -30,14 +24,7 @@ const DataTable_TableHeadCell = ({ refs: { tableHeadCellRefs }, setHoveredColumn, } = table; - const { - columnSizingInfo, - density, - draggingColumn, - grouping, - hoveredColumn, - showColumnFilters, - } = getState(); + const { columnSizingInfo, density, draggingColumn, grouping, hoveredColumn, showColumnFilters } = getState(); const { column } = header; const { columnDef } = column; const { columnDefType } = columnDef; @@ -51,23 +38,17 @@ const DataTable_TableHeadCell = ({ ...rest, }; - const isColumnPinned = - enableColumnPinning && - columnDef.columnDefType !== 'group' && - column.getIsPinned(); + const isColumnPinned = enableColumnPinning && columnDef.columnDefType !== "group" && column.getIsPinned(); const showColumnActions = - (enableColumnActions || columnDef.enableColumnActions) && - columnDef.enableColumnActions !== false; + (enableColumnActions || columnDef.enableColumnActions) && columnDef.enableColumnActions !== false; const showDragHandle = enableColumnDragging !== false && columnDef.enableColumnDragging !== false && (enableColumnDragging || (enableColumnOrdering && columnDef.enableColumnOrdering !== false) || - (enableGrouping && - columnDef.enableGrouping !== false && - !grouping.includes(column.id))); + (enableGrouping && columnDef.enableGrouping !== false && !grouping.includes(column.id))); const headerPL = useMemo(() => { let pl = 0; @@ -80,41 +61,37 @@ const DataTable_TableHeadCell = ({ const draggingBorders = useMemo(() => { const showResizeBorder = columnSizingInfo.isResizingColumn === column.id && - columnResizeMode === 'onChange' && + columnResizeMode === "onChange" && !header.subHeaders.length; const borderStyle = showResizeBorder ? `2px solid ${draggingBorderColor} !important` : draggingColumn?.id === column.id - ? `1px dashed ${theme.palette.grey[500]}` - : hoveredColumn?.id === column.id - ? `2px dashed ${draggingBorderColor}` - : undefined; + ? `1px dashed ${theme.palette.grey[500]}` + : hoveredColumn?.id === column.id + ? `2px dashed ${draggingBorderColor}` + : undefined; if (showResizeBorder) { - return columnResizeDirection === 'ltr' - ? { borderRight: borderStyle } - : { borderLeft: borderStyle }; + return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle }; } const draggingBorders = borderStyle ? { - borderLeft: borderStyle, - borderRight: borderStyle, - borderTop: borderStyle, - } + borderLeft: borderStyle, + borderRight: borderStyle, + borderTop: borderStyle, + } : undefined; return draggingBorders; }, [draggingColumn, hoveredColumn, columnSizingInfo.isResizingColumn]); const handleDragEnter = (_e) => { - if (enableGrouping && hoveredColumn?.id === 'drop-zone') { + if (enableGrouping && hoveredColumn?.id === "drop-zone") { setHoveredColumn(null); } - if (enableColumnOrdering && draggingColumn && columnDefType !== 'group') { - setHoveredColumn( - columnDef.enableColumnOrdering !== false ? column : null, - ); + if (enableColumnOrdering && draggingColumn && columnDefType !== "group") { + setHoveredColumn(columnDef.enableColumnOrdering !== false ? column : null); } }; @@ -124,7 +101,6 @@ const DataTable_TableHeadCell = ({ } }; - const HeaderElement = parseFromValuesOrFunc(columnDef.Header, { column, @@ -132,12 +108,9 @@ const DataTable_TableHeadCell = ({ table, }) ?? columnDef.header; - const columnRelativeDepth = header.depth - column.depth; - if ( - columnRelativeDepth > 1 - ) { + if (columnRelativeDepth > 1) { return null; } @@ -149,13 +122,7 @@ const DataTable_TableHeadCell = ({ return ( { if (node) { tableHeadCellRefs.current[column.id] = node; - if (columnDefType !== 'group') { + if (columnDefType !== "group") { columnVirtualizer?.measureElement?.(node); } } }} {...tableCellProps} sx={(theme) => ({ - '& :hover': { - '.MuiButtonBase-root': { + "& :hover": { + ".MuiButtonBase-root": { opacity: 1, }, }, - flexDirection: layoutMode?.startsWith('grid') ? 'column' : undefined, - fontWeight: 'bold', - overflow: 'visible', + flexDirection: layoutMode?.startsWith("grid") ? "column" : undefined, + fontWeight: "bold", + overflow: "visible", p: - density === 'compact' - ? '0.5rem' - : density === 'comfortable' - ? columnDefType === 'display' - ? '0.75rem' - : '1rem' - : columnDefType === 'display' - ? '1rem 1.25rem' - : '1.5rem', - pb: - columnDefType === 'display' - ? 0 - : showColumnFilters || density === 'compact' - ? '0.4rem' - : '0.6rem', + density === "compact" + ? "0.5rem" + : density === "comfortable" + ? columnDefType === "display" + ? "0.75rem" + : "1rem" + : columnDefType === "display" + ? "1rem 1.25rem" + : "1.5rem", + pb: columnDefType === "display" ? 0 : showColumnFilters || density === "compact" ? "0.4rem" : "0.6rem", pt: - columnDefType === 'group' || density === 'compact' - ? '0.25rem' - : density === 'comfortable' - ? '.75rem' - : '1.25rem', - userSelect: enableMultiSort && column.getCanSort() ? 'none' : undefined, - verticalAlign: 'middle', + columnDefType === "group" || density === "compact" + ? "0.25rem" + : density === "comfortable" + ? ".75rem" + : "1.25rem", + userSelect: enableMultiSort && column.getCanSort() ? "none" : undefined, + verticalAlign: "middle", ...getCommonMRTCellStyles({ column, header, @@ -212,72 +174,65 @@ const DataTable_TableHeadCell = ({ theme, }), ...draggingBorders, - } - )} + })} > {tableCellProps.children ?? ( {HeaderElement} - {(column.getCanSort() && columnDefType !== 'group') && ( - + {column.getCanSort() && columnDefType !== "group" && ( + )} )} ); - -} -export default DataTable_TableHeadCell; \ No newline at end of file +}; +export default DataTable_TableHeadCell; diff --git a/src/core/components/DataTable/head/TableHeadRow.js b/src/core/components/DataTable/head/TableHeadRow.js index f876cf1..512147a 100644 --- a/src/core/components/DataTable/head/TableHeadRow.js +++ b/src/core/components/DataTable/head/TableHeadRow.js @@ -6,19 +6,15 @@ const DataTable_TableHeadRow = ({ columnVirtualizer, headerGroup, table, + index, // Add index prop ...rest }) => { const { - options: { - enableStickyHeader, - layoutMode, - mrtTheme: { baseBackgroundColor }, - muiTableHeadRowProps, - }, + options: { enableStickyHeader, layoutMode, muiTableHeadRowProps }, } = table; + const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = columnVirtualizer ?? {}; - const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = - columnVirtualizer ?? {}; + const backgroundColor = index % 2 === 0 ? "#015688" : "#ff5c0f"; const tableRowProps = { ...parseFromValuesOrFunc(muiTableHeadRowProps, { @@ -26,51 +22,37 @@ const DataTable_TableHeadRow = ({ table, }), ...rest, + sx: (theme) => ({ + // Access theme from the sx function + ...(parseFromValuesOrFunc(muiTableHeadRowProps?.sx, theme) || {}), + backgroundColor, // Apply background color + display: layoutMode?.startsWith("grid") ? "flex" : undefined, + position: enableStickyHeader && layoutMode === "semantic" ? "sticky" : "relative", + top: 0, + }), }; return ( - ({ - backgroundColor: baseBackgroundColor, - display: layoutMode?.startsWith('grid') ? 'flex' : undefined, - position: - enableStickyHeader && layoutMode === 'semantic' - ? 'sticky' - : 'relative', - top: 0, - ...(parseFromValuesOrFunc(tableRowProps?.sx, theme)), + + {virtualPaddingLeft && } + {(virtualColumns ?? headerGroup.headers).map((headerOrVirtualHeader, staticColumnIndex) => { + const header = columnVirtualizer + ? headerGroup.headers[headerOrVirtualHeader.index] + : headerOrVirtualHeader; + + return header ? ( + + ) : null; })} - > - {virtualPaddingLeft ? ( - - ) : null} - {(virtualColumns ?? headerGroup.headers).map( - (headerOrVirtualHeader, staticColumnIndex) => { - let header = headerOrVirtualHeader; - - if (columnVirtualizer) { - staticColumnIndex = (headerOrVirtualHeader) - .index; - header = headerGroup.headers[staticColumnIndex]; - } - - return header ? ( - - ) : null; - }, - )} - {virtualPaddingRight ? ( - - ) : null} + {virtualPaddingRight && } ); +}; -} -export default DataTable_TableHeadRow \ No newline at end of file +export default DataTable_TableHeadRow; diff --git a/src/core/components/DataTable/index.js b/src/core/components/DataTable/index.js index f453ade..f387d06 100644 --- a/src/core/components/DataTable/index.js +++ b/src/core/components/DataTable/index.js @@ -1,123 +1,12 @@ -import { useMaterialReactTable } from "material-react-table"; import DataTable_Main from "./Main"; -import { FA_DATATABLE_LOCALIZATION } from "./localization/fa/datatable"; -import CustomToolbar from "@/components/CustomToolbar"; -import useTableSetting from "@/lib/hooks/useTableSetting"; -import {flattenArrayOfObjects} from "@/core/utils/flattenArrayOfObjects"; - -const data = [ - { - name: { - firstName: 'John', - lastName: 'Doe', - }, - address: '261 Erdman Ford', - city: 'East Daphne', - state: 'Kentucky', - }, - { - name: { - firstName: 'Jane', - lastName: 'Doe', - }, - address: '769 Dominic Grove', - city: 'Columbus', - state: 'Ohio', - }, - { - name: { - firstName: 'Joe', - lastName: 'Doe', - }, - address: '566 Brakus Inlet', - city: 'South Linda', - state: 'West Virginia', - }, - { - name: { - firstName: 'Kevin', - lastName: 'Vandy', - }, - address: '722 Emie Stream', - city: 'Lincoln', - state: 'Nebraska', - }, - { - name: { - firstName: 'Joshua', - lastName: 'Rolluffs', - }, - address: '32188 Larkin Turnpike', - city: 'Charleston', - state: 'South Carolina', - }, -]; +import DataTableProvider from "@/lib/contexts/DataTable"; const DataTable = (props) => { - const { userId, pageName, tableName, columns, initialStateProps } = props - const { settingStore, hideAction, sortAction } = useTableSetting(); - const flatColumns = flattenArrayOfObjects(columns,'columns') - - const onColumnVisibilityChange = (event) => { - const settingValue = event(); - hideAction(userId, pageName, tableName, settingValue, flatColumns); - }; - const onSortingChange = (event) => { - const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); - sortAction(userId, pageName, tableName, settingValue, flatColumns); - } - - - const table = useMaterialReactTable({ - localization: FA_DATATABLE_LOCALIZATION, - columns, - data: data, - // manualSorting: true, - renderTopToolbarCustomActions: ({ table }) => (<> - - ), - initialState: { - density: 'compact', - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [], - ...initialStateProps - }, - state: { - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [] - }, - muiTableHeadProps: { - sx: { - borderTop: "1px solid #e1e1e1", - borderBottom: "2px solid #e1e1e1", - } - }, - muiTableHeadCellProps: { - sx: { - color: "primary.main", - borderLeft: "1px solid #e1e1e1", - "&:first-of-type": { - borderLeft: "unset" - } - }, - }, - muiTableBodyCellProps: { - sx: { - borderLeft: "1px solid #e1e1e1", - "&:first-of-type": { - borderLeft: "unset" - } - }, - }, - onColumnVisibilityChange: onColumnVisibilityChange, - onSortingChange: onSortingChange, - ...props - }) - - - return ; + return ( + + + + ); }; export default DataTable; diff --git a/src/core/components/DataTable/localization/fa/datatable.js b/src/core/components/DataTable/localization/fa/datatable.js index f80b7e0..e36f366 100644 --- a/src/core/components/DataTable/localization/fa/datatable.js +++ b/src/core/components/DataTable/localization/fa/datatable.js @@ -67,8 +67,7 @@ export const FA_DATATABLE_LOCALIZATION = { rowsPerPage: "ردیف در هر صفحه", save: "ذخیره", search: "جستجو", - selectedCountOfRowCountRowsSelected: - "{selectedCount} از {rowCount} ردیف انتخاب شده", + selectedCountOfRowCountRowsSelected: "{selectedCount} از {rowCount} ردیف انتخاب شده", select: "انتخاب", showAll: "نمایش همه", showAllColumns: "نمایش همه ستون‌ها", @@ -89,4 +88,4 @@ export const FA_DATATABLE_LOCALIZATION = { unpin: "رها کردن", unpinAll: "رها کردن همه", unsorted: "بدون مرتب سازی", -}; \ No newline at end of file +}; diff --git a/src/core/components/DataTable/menus/ActionMenuItem.js b/src/core/components/DataTable/menus/ActionMenuItem.js index 2b208b9..012fcc5 100644 --- a/src/core/components/DataTable/menus/ActionMenuItem.js +++ b/src/core/components/DataTable/menus/ActionMenuItem.js @@ -1,12 +1,6 @@ import { Box, IconButton, ListItemIcon, MenuItem } from "@mui/material"; -const DataTable_ActionMenuItem = ({ - icon, - label, - onOpenSubMenu, - table, - ...rest -}) => { +const DataTable_ActionMenuItem = ({ icon, label, onOpenSubMenu, table, ...rest }) => { const { options: { icons: { ArrowRightIcon }, @@ -16,35 +10,29 @@ const DataTable_ActionMenuItem = ({ return ( {icon} {label} {onOpenSubMenu && ( - + )} ); - -} -export default DataTable_ActionMenuItem \ No newline at end of file +}; +export default DataTable_ActionMenuItem; diff --git a/src/core/components/DataTable/menus/CellActionMenu.js b/src/core/components/DataTable/menus/CellActionMenu.js index 36638e0..5b27ca9 100644 --- a/src/core/components/DataTable/menus/CellActionMenu.js +++ b/src/core/components/DataTable/menus/CellActionMenu.js @@ -2,10 +2,7 @@ import { parseFromValuesOrFunc } from "@/core/utils/utils"; import { Menu } from "@mui/material"; import DataTable_ActionMenuItem from "./ActionMenuItem"; -const DataTable_CellActionMenu = ({ - table, - ...rest -}) => { +const DataTable_CellActionMenu = ({ table, ...rest }) => { const { getState, options: { @@ -32,12 +29,11 @@ const DataTable_CellActionMenu = ({ }; const internalMenuItems = [ - (parseFromValuesOrFunc(enableClickToCopy, cell) === 'context-menu' || - parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === - 'context-menu') && ( + (parseFromValuesOrFunc(enableClickToCopy, cell) === "context-menu" || + parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === "context-menu") && ( } - key={'mrt-copy'} + key={"mrt-copy"} label={localization.copy} onClick={(event) => { event.stopPropagation(); @@ -47,10 +43,10 @@ const DataTable_CellActionMenu = ({ table={table} /> ), - parseFromValuesOrFunc(enableEditing, row) && editDisplayMode === 'cell' && ( + parseFromValuesOrFunc(enableEditing, row) && editDisplayMode === "cell" && ( } - key={'mrt-edit'} + key={"mrt-edit"} label={localization.edit} onClick={() => { openEditingCell({ cell, table }); @@ -71,14 +67,13 @@ const DataTable_CellActionMenu = ({ }; const menuItems = - columnDef.renderCellActionMenuItems?.(renderActionProps) ?? - renderCellActionMenuItems?.(renderActionProps); + columnDef.renderCellActionMenuItems?.(renderActionProps) ?? renderCellActionMenuItems?.(renderActionProps); return ( (!!menuItems?.length || !!internalMenuItems?.length) && ( ) ); - -} -export default DataTable_CellActionMenu \ No newline at end of file +}; +export default DataTable_CellActionMenu; diff --git a/src/core/components/DataTable/menus/ShowHideColumnsMenu.js b/src/core/components/DataTable/menus/ShowHideColumnsMenu.js index 12efae8..cb0423c 100644 --- a/src/core/components/DataTable/menus/ShowHideColumnsMenu.js +++ b/src/core/components/DataTable/menus/ShowHideColumnsMenu.js @@ -2,11 +2,7 @@ import { Box, Button, Divider, Menu } from "@mui/material"; import { useMemo, useState } from "react"; import DataTable_ShowHideColumnsMenuItems from "./ShowHideColumnsMenuItems"; -const DataTable_ShowHideColumnsMenu = ({ anchorEl, - setAnchorEl, - table, - ...rest -}) => { +const DataTable_ShowHideColumnsMenu = ({ anchorEl, setAnchorEl, table, ...rest }) => { const { getAllColumns, getAllLeafColumns, @@ -36,14 +32,11 @@ const DataTable_ShowHideColumnsMenu = ({ anchorEl, const allColumns = useMemo(() => { const columns = getAllColumns(); - if ( - columnOrder.length > 0 && - !columns.some((col) => col.columnDef.columnDefType === 'group') - ) { + if (columnOrder.length > 0 && !columns.some((col) => col.columnDef.columnDefType === "group")) { return [ ...getLeftLeafColumns(), ...Array.from(new Set(columnOrder)).map((colId) => - getCenterLeafColumns().find((col) => col?.id === colId), + getCenterLeafColumns().find((col) => col?.id === colId) ), ...getRightLeafColumns(), ].filter(Boolean); @@ -58,16 +51,14 @@ const DataTable_ShowHideColumnsMenu = ({ anchorEl, getRightLeafColumns(), ]); - const isNestedColumns = allColumns.some( - (col) => col.columnDef.columnDefType === 'group', - ); + const isNestedColumns = allColumns.some((col) => col.columnDef.columnDefType === "group"); const [hoveredColumn, setHoveredColumn] = useState(null); return ( {enableHiding && ( - )} {enableColumnOrdering && ( - )} {enableColumnPinning && ( - )} {enableHiding && ( - )} @@ -136,5 +112,5 @@ const DataTable_ShowHideColumnsMenu = ({ anchorEl, ))} ); -} -export default DataTable_ShowHideColumnsMenu \ No newline at end of file +}; +export default DataTable_ShowHideColumnsMenu; diff --git a/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js b/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js index 58425d9..97c2e5d 100644 --- a/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js +++ b/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js @@ -30,7 +30,7 @@ const DataTable_ShowHideColumnsMenuItems = ({ const switchChecked = column.getIsVisible(); const handleToggleColumnHidden = (column) => { - if (columnDefType === 'group') { + if (columnDefType === "group") { column?.columns?.forEach?.((childColumn) => { childColumn.toggleVisibility(!switchChecked); }); @@ -78,29 +78,29 @@ const DataTable_ShowHideColumnsMenuItems = ({ ref={menuItemRef} {...rest} sx={(theme) => ({ - alignItems: 'center', - justifyContent: 'flex-start', + alignItems: "center", + justifyContent: "flex-start", my: 0, opacity: isDragging ? 0.5 : 1, outline: isDragging ? `2px dashed ${theme.palette.grey[500]}` : hoveredColumn?.id === column.id - ? `2px dashed ${draggingBorderColor}` - : 'none', - outlineOffset: '-2px', + ? `2px dashed ${draggingBorderColor}` + : "none", + outlineOffset: "-2px", pl: `${(column.depth + 0.5) * 2}rem`, - py: '6px', - ...(parseFromValuesOrFunc(rest?.sx, theme)), + py: "6px", + ...parseFromValuesOrFunc(rest?.sx, theme), })} > - {columnDefType !== 'group' && + {columnDefType !== "group" && enableColumnOrdering && !isNestedColumns && (columnDef.enableColumnOrdering !== false ? ( @@ -110,7 +110,7 @@ const DataTable_ShowHideColumnsMenuItems = ({ table={table} /> ) : ( - + ))} {enableHiding ? ( + } @@ -136,9 +133,7 @@ const DataTable_ShowHideColumnsMenuItems = ({ onChange={() => handleToggleColumnHidden(column)} /> ) : ( - - {columnDef.header} - + {columnDef.header} )} @@ -155,6 +150,5 @@ const DataTable_ShowHideColumnsMenuItems = ({ ))} ); - -} -export default DataTable_ShowHideColumnsMenuItems; \ No newline at end of file +}; +export default DataTable_ShowHideColumnsMenuItems; diff --git a/src/core/components/DataTable/refactor/RefactorTable.jsx b/src/core/components/DataTable/refactor/RefactorTable.jsx new file mode 100644 index 0000000..49217a0 --- /dev/null +++ b/src/core/components/DataTable/refactor/RefactorTable.jsx @@ -0,0 +1,26 @@ +"use client"; +import { IconButton, Tooltip } from "@mui/material"; +import RestartAltIcon from "@mui/icons-material/RestartAlt"; +import useTableSetting from "@/lib/hooks/useTableSetting"; +import { useState } from "react"; + +function RefactorTable() { + const { refactorAction } = useTableSetting(); + const [userId, setUserId] = useState(0); + const [pageName, setPageName] = useState("testPage"); + const [tableName, setTableName] = useState("testTable"); + + const refactor = () => { + refactorAction(userId, pageName, tableName); + }; + + return ( + + + + + + ); +} + +export default RefactorTable; diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js index db3bbec..ede80b3 100644 --- a/src/core/components/DataTable/table/Paper.js +++ b/src/core/components/DataTable/table/Paper.js @@ -5,74 +5,79 @@ import DataTable_TopToolbar from "../toolbar/TopToolbar"; import DataTable_TableContainer from "./TableContainer"; const DataTable_Paper = ({ table, ...rest }) => { - const { - getState, - options: { - enableBottomToolbar, - enableTopToolbar, - mrtTheme: { baseBackgroundColor }, - muiTablePaperProps, - renderBottomToolbar, - renderTopToolbar, - }, - refs: { tablePaperRef }, - } = table; + const { + getState, + options: { + enableBottomToolbar, + enableTopToolbar, + mrtTheme: { baseBackgroundColor }, + muiTablePaperProps, + renderBottomToolbar, + renderTopToolbar, + }, + refs: { tablePaperRef }, + } = table; - const { isFullScreen } = getState(); + const { isFullScreen } = getState(); - const paperProps = { - ...parseFromValuesOrFunc(muiTablePaperProps, { table }), - ...rest, - }; + const paperProps = { + ...parseFromValuesOrFunc(muiTablePaperProps, { table }), + ...rest, + }; - return ( - { - tablePaperRef.current = ref; - if (paperProps?.ref) { - //@ts-ignore - paperProps.ref.current = ref; - } - }} - style={{ - ...(isFullScreen - ? { - bottom: 0, - height: '100dvh', - left: 0, - margin: 0, - maxHeight: '100dvh', - maxWidth: '100dvw', - padding: 0, - position: 'fixed', - right: 0, - top: 0, - width: '100dvw', - zIndex: 999, - } - : {}), - ...paperProps?.style, - }} - sx={(theme) => ({ - backgroundColor: baseBackgroundColor, - backgroundImage: 'unset', - overflow: 'hidden', - transition: 'all 100ms ease-in-out', - ...(parseFromValuesOrFunc(paperProps?.sx, theme)), - })} - > - {enableTopToolbar && - (parseFromValuesOrFunc(renderTopToolbar, { table }) ?? ( - - ))} - - {enableBottomToolbar && - (parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? ( - - ))} - - ); + return ( + { + tablePaperRef.current = ref; + if (paperProps?.ref) { + //@ts-ignore + paperProps.ref.current = ref; + } + }} + style={{ + ...(isFullScreen + ? { + bottom: 0, + height: "100dvh", + left: 0, + margin: 0, + maxHeight: "100dvh", + maxWidth: "100dvw", + padding: 0, + position: "fixed", + right: 0, + top: 0, + width: "100dvw", + zIndex: 999, + } + : {}), + ...paperProps?.style, + }} + sx={(theme) => ({ + backgroundColor: baseBackgroundColor, + backgroundImage: "unset", + overflow: "hidden", + transition: "all 100ms ease-in-out", + ...parseFromValuesOrFunc(paperProps?.sx, theme), + })} + > + {enableTopToolbar && + (parseFromValuesOrFunc(renderTopToolbar, { table }) ?? ( + + ))} + + {enableBottomToolbar && + (parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? )} + + ); }; export default DataTable_Paper; diff --git a/src/core/components/DataTable/table/Table.js b/src/core/components/DataTable/table/Table.js index ca49d0c..1bf6b69 100644 --- a/src/core/components/DataTable/table/Table.js +++ b/src/core/components/DataTable/table/Table.js @@ -5,10 +5,7 @@ import { useMemo } from "react"; import DataTable_TableBody, { Memo_DataTable_TableBody } from "../body/TableBody"; import DataTable_TableHead from "../head/TableHead"; -const DataTable_Table = ({ - table, - ...rest -}) => { +const DataTable_Table = ({ table, ...rest }) => { const { getFlatHeaders, getState, @@ -23,8 +20,7 @@ const DataTable_Table = ({ renderCaption, }, } = table; - const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } = - getState(); + const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } = getState(); const tableProps = { ...parseFromValuesOrFunc(muiTableProps, { table }), @@ -58,14 +54,14 @@ const DataTable_Table = ({ {...tableProps} style={{ ...columnSizeVars, ...tableProps?.style }} sx={(theme) => ({ - display: layoutMode?.startsWith('grid') ? 'grid' : undefined, - position: 'relative', - ...(parseFromValuesOrFunc(tableProps?.sx, theme)), + display: layoutMode?.startsWith("grid") ? "grid" : undefined, + position: "relative", + ...parseFromValuesOrFunc(tableProps?.sx, theme), })} > {!!Caption && {Caption}} {enableTableHead && } - {memoMode === 'table-body' || columnSizingInfo.isResizingColumn ? ( + {memoMode === "table-body" || columnSizingInfo.isResizingColumn ? ( ) : ( @@ -73,5 +69,5 @@ const DataTable_Table = ({ {/* {enableTableFooter && } */} ); -} -export default DataTable_Table \ No newline at end of file +}; +export default DataTable_Table; diff --git a/src/core/components/DataTable/table/TableContainer.js b/src/core/components/DataTable/table/TableContainer.js index aa4b625..bc1d80c 100644 --- a/src/core/components/DataTable/table/TableContainer.js +++ b/src/core/components/DataTable/table/TableContainer.js @@ -5,31 +5,17 @@ import DataTable_CellActionMenu from "../menus/CellActionMenu"; import DataTable_Table from "./Table"; import DataTable_TableLoadingOverlay from "./TableLoadingOverlay"; -const useIsomorphicLayoutEffect = - typeof window !== 'undefined' ? useLayoutEffect : useEffect; +const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; -const DataTable_TableContainer = ({ - table, - ...rest -}) => { +const DataTable_TableContainer = ({ table, ...rest }) => { const { getState, - options: { - enableCellActions, - enableStickyHeader, - muiTableContainerProps, - }, + options: { enableCellActions, enableStickyHeader, muiTableContainerProps }, refs: { bottomToolbarRef, tableContainerRef, topToolbarRef }, } = table; - const { - actionCell, - isFullScreen, - isLoading, - showLoadingOverlay, - } = getState(); + const { actionCell, isFullScreen, isLoading, showLoadingOverlay } = getState(); - const loading = - showLoadingOverlay !== false && (isLoading || showLoadingOverlay); + const loading = showLoadingOverlay !== false && (isLoading || showLoadingOverlay); const [totalToolbarHeight, setTotalToolbarHeight] = useState(0); @@ -41,15 +27,9 @@ const DataTable_TableContainer = ({ }; useIsomorphicLayoutEffect(() => { - const topToolbarHeight = - typeof document !== 'undefined' - ? topToolbarRef.current?.offsetHeight ?? 0 - : 0; + const topToolbarHeight = typeof document !== "undefined" ? topToolbarRef.current?.offsetHeight ?? 0 : 0; - const bottomToolbarHeight = - typeof document !== 'undefined' - ? bottomToolbarRef?.current?.offsetHeight ?? 0 - : 0; + const bottomToolbarHeight = typeof document !== "undefined" ? bottomToolbarRef?.current?.offsetHeight ?? 0 : 0; setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight); }); @@ -57,7 +37,7 @@ const DataTable_TableContainer = ({ return ( { if (node) { @@ -69,19 +49,17 @@ const DataTable_TableContainer = ({ } }} style={{ - maxHeight: isFullScreen - ? `calc(100vh - ${totalToolbarHeight}px)` - : undefined, + maxHeight: isFullScreen ? `calc(100vh - ${totalToolbarHeight}px)` : undefined, ...tableContainerProps?.style, }} sx={(theme) => ({ maxHeight: enableStickyHeader ? `clamp(350px, calc(100vh - ${totalToolbarHeight}px), 9999px)` : undefined, - maxWidth: '100%', - overflow: 'auto', - position: 'relative', - ...(parseFromValuesOrFunc(tableContainerProps?.sx, theme)), + maxWidth: "100%", + overflow: "auto", + position: "relative", + ...parseFromValuesOrFunc(tableContainerProps?.sx, theme), })} > {loading ? : null} @@ -89,6 +67,5 @@ const DataTable_TableContainer = ({ {enableCellActions && actionCell && } ); - -} -export default DataTable_TableContainer \ No newline at end of file +}; +export default DataTable_TableContainer; diff --git a/src/core/components/DataTable/table/TableLoadingOverlay.js b/src/core/components/DataTable/table/TableLoadingOverlay.js index 55e4ae5..0c417dd 100644 --- a/src/core/components/DataTable/table/TableLoadingOverlay.js +++ b/src/core/components/DataTable/table/TableLoadingOverlay.js @@ -1,9 +1,6 @@ import { Box, CircularProgress } from "@mui/material"; -const DataTable_TableLoadingOverlay = ({ - table, - ...rest -}) => { +const DataTable_TableLoadingOverlay = ({ table, ...rest }) => { const { options: { localization, @@ -20,17 +17,17 @@ const DataTable_TableLoadingOverlay = ({ return ( @@ -43,6 +40,5 @@ const DataTable_TableLoadingOverlay = ({ )} ); - -} -export default DataTable_TableLoadingOverlay \ No newline at end of file +}; +export default DataTable_TableLoadingOverlay; diff --git a/src/core/components/DataTable/toolbar/BottomToolbar.js b/src/core/components/DataTable/toolbar/BottomToolbar.js index 15e7f5a..ced2c06 100644 --- a/src/core/components/DataTable/toolbar/BottomToolbar.js +++ b/src/core/components/DataTable/toolbar/BottomToolbar.js @@ -3,23 +3,15 @@ import { Box, alpha, useMediaQuery } from "@mui/material"; import DataTable_LinearProgressBar from "./LinearProgressBar"; import DataTable_TablePagination from "./TablePagination"; -const DataTable_BottomToolbar = ({ - table, - ...rest -}) => { +const DataTable_BottomToolbar = ({ table, ...rest }) => { const { getState, - options: { - enablePagination, - muiBottomToolbarProps, - positionPagination, - renderBottomToolbarCustomActions, - }, + options: { enablePagination, muiBottomToolbarProps, positionPagination, renderBottomToolbarCustomActions }, refs: { bottomToolbarRef }, } = table; const { isFullScreen } = getState(); - const isMobile = useMediaQuery('(max-width:720px)'); + const isMobile = useMediaQuery("(max-width:720px)"); const toolbarProps = { ...parseFromValuesOrFunc(muiBottomToolbarProps, { table }), ...rest, @@ -40,49 +32,41 @@ const DataTable_BottomToolbar = ({ }} sx={(theme) => ({ ...getCommonToolbarStyles({ table, theme }), - bottom: isFullScreen ? '0' : undefined, - boxShadow: `0 1px 2px -1px ${alpha( - theme.palette.grey[700], - 0.5, - )} inset`, + bottom: isFullScreen ? "0" : undefined, + boxShadow: `0 1px 2px -1px ${alpha(theme.palette.grey[700], 0.5)} inset`, left: 0, - position: isFullScreen ? 'fixed' : 'relative', + position: isFullScreen ? "fixed" : "relative", right: 0, - ...(parseFromValuesOrFunc(toolbarProps?.sx, theme)), + ...parseFromValuesOrFunc(toolbarProps?.sx, theme), })} > - {renderBottomToolbarCustomActions ? ( - renderBottomToolbarCustomActions({ table }) - ) : ( - - )} + {renderBottomToolbarCustomActions ? renderBottomToolbarCustomActions({ table }) : } - {enablePagination && - ['both', 'bottom'].includes(positionPagination ?? '') && ( - - )} + {enablePagination && ["both", "bottom"].includes(positionPagination ?? "") && ( + + )} ); -} -export default DataTable_BottomToolbar \ No newline at end of file +}; +export default DataTable_BottomToolbar; diff --git a/src/core/components/DataTable/toolbar/LinearProgressBar.js b/src/core/components/DataTable/toolbar/LinearProgressBar.js index cdcbc0a..74c465f 100644 --- a/src/core/components/DataTable/toolbar/LinearProgressBar.js +++ b/src/core/components/DataTable/toolbar/LinearProgressBar.js @@ -1,11 +1,7 @@ import { parseFromValuesOrFunc } from "@/core/utils/utils"; import { Collapse, LinearProgress } from "@mui/material"; -const DataTable_LinearProgressBar = ({ - isTopToolbar, - table, - ...rest -}) => { +const DataTable_LinearProgressBar = ({ isTopToolbar, table, ...rest }) => { const { getState, options: { muiLinearProgressProps }, @@ -26,19 +22,19 @@ const DataTable_LinearProgressBar = ({ mountOnEnter sx={{ bottom: isTopToolbar ? 0 : undefined, - position: 'absolute', + position: "absolute", top: !isTopToolbar ? 0 : undefined, - width: '100%', + width: "100%", }} unmountOnExit > ); -} -export default DataTable_LinearProgressBar \ No newline at end of file +}; +export default DataTable_LinearProgressBar; diff --git a/src/core/components/DataTable/toolbar/TablePagination.js b/src/core/components/DataTable/toolbar/TablePagination.js index cd70fda..6492b41 100644 --- a/src/core/components/DataTable/toolbar/TablePagination.js +++ b/src/core/components/DataTable/toolbar/TablePagination.js @@ -1,16 +1,23 @@ import { flipIconStyles, getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils"; import { useTheme } from "@emotion/react"; -import { Box, IconButton, InputLabel, MenuItem, Pagination, PaginationItem, Select, Tooltip, Typography, useMediaQuery } from "@mui/material"; +import { + Box, + IconButton, + InputLabel, + MenuItem, + Pagination, + PaginationItem, + Select, + Tooltip, + Typography, + useMediaQuery, +} from "@mui/material"; const defaultRowsPerPage = [5, 10, 15, 20, 25, 30, 50, 100]; -const DataTable_TablePagination = ({ - position = 'bottom', - table, - ...rest -}) => { +const DataTable_TablePagination = ({ position = "bottom", table, ...rest }) => { const theme = useTheme(); - const isMobile = useMediaQuery('(max-width: 720px)'); + const isMobile = useMediaQuery("(max-width: 720px)"); const { getState, @@ -64,26 +71,21 @@ const DataTable_TablePagination = ({ {showRowsPerPage && ( - + {localization.rowsPerPage} @@ -92,22 +94,19 @@ const DataTable_TablePagination = ({ disableUnderline disabled={disabled} inputProps={{ - 'aria-label': localization.rowsPerPage, - id: 'mrt-rows-per-page', + "aria-label": localization.rowsPerPage, + id: "mrt-rows-per-page", }} label={localization.rowsPerPage} - onChange={(event) => - table.setPageSize(+(event.target.value)) - } + onChange={(event) => table.setPageSize(+event.target.value)} sx={{ mb: 0 }} value={pageSize} variant="standard" {...SelectProps} > {rowsPerPageOptions.map((option) => { - const value = typeof option !== 'number' ? option.value : option; - const label = - typeof option !== 'number' ? option.label : `${option}`; + const value = typeof option !== "number" ? option.value : option; + const label = typeof option !== "number" ? option.label : `${option}`; return ( SelectProps?.children ?? (SelectProps?.native ? ( @@ -124,7 +123,7 @@ const DataTable_TablePagination = ({ )} - {paginationDisplayMode === 'pages' ? ( + {paginationDisplayMode === "pages" ? ( - ) : paginationDisplayMode === 'default' ? ( + ) : paginationDisplayMode === "default" ? ( <> {`${lastRowIndex === 0 ? 0 : (firstRowIndex + 1).toLocaleString() - }-${lastRowIndex.toLocaleString()} ${localization.of - } ${totalRowCount.toLocaleString()}`} + >{`${ + lastRowIndex === 0 ? 0 : (firstRowIndex + 1).toLocaleString() + }-${lastRowIndex.toLocaleString()} ${ + localization.of + } ${totalRowCount.toLocaleString()}`} {showFirstButton && ( @@ -213,5 +214,5 @@ const DataTable_TablePagination = ({ ) : null} ); -} -export default DataTable_TablePagination \ No newline at end of file +}; +export default DataTable_TablePagination; diff --git a/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js b/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js index 606add0..9250b89 100644 --- a/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js +++ b/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js @@ -16,32 +16,29 @@ const DataTable_ToolbarInternalButtons = ({ table, ...rest }) => { }, } = table; - return ( ({ - alignItems: 'center', - display: 'flex', + alignItems: "center", + display: "flex", zIndex: 3, - ...(parseFromValuesOrFunc(rest?.sx, theme)), + ...parseFromValuesOrFunc(rest?.sx, theme), })} > {renderToolbarInternalActions?.({ table, }) ?? ( - <> - {enableFilters && - enableColumnFilters && - columnFilterDisplayMode !== 'popover' && ( - - )} - {(enableHiding || enableColumnOrdering || enableColumnPinning) && ( - - )} - - )} + <> + {enableFilters && enableColumnFilters && columnFilterDisplayMode !== "popover" && ( + + )} + {(enableHiding || enableColumnOrdering || enableColumnPinning) && ( + + )} + + )} ); -} -export default DataTable_ToolbarInternalButtons \ No newline at end of file +}; +export default DataTable_ToolbarInternalButtons; diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js index 4eb0aba..b0e5297 100644 --- a/src/core/components/DataTable/toolbar/TopToolbar.js +++ b/src/core/components/DataTable/toolbar/TopToolbar.js @@ -3,8 +3,10 @@ import { Box, useMediaQuery } from "@mui/material"; import DataTable_LinearProgressBar from "./LinearProgressBar"; import DataTable_TablePagination from "./TablePagination"; import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons"; +import FilterColumn from "@/core/components/DataTable/filter"; +import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable"; -const DataTable_TopToolbar = ({ table }) => { +const DataTable_TopToolbar = ({ table, columns, table_url, user_id, page_name, table_name }) => { const { getState, options: { @@ -18,15 +20,12 @@ const DataTable_TopToolbar = ({ table }) => { } = table; const { isFullScreen, showGlobalFilter } = getState(); - const isMobile = useMediaQuery('(max-width:720px)'); - const isTablet = useMediaQuery('(max-width:1024px)'); + const isMobile = useMediaQuery("(max-width:720px)"); + const isTablet = useMediaQuery("(max-width:1024px)"); const toolbarProps = parseFromValuesOrFunc(muiTopToolbarProps, { table }); - const stackAlertBanner = - isMobile || - !!renderTopToolbarCustomActions || - (showGlobalFilter && isTablet); + const stackAlertBanner = isMobile || !!renderTopToolbarCustomActions || (showGlobalFilter && isTablet); return ( { }} sx={(theme) => ({ ...getCommonToolbarStyles({ table, theme }), - position: isFullScreen ? 'sticky' : 'relative', - top: isFullScreen ? '0' : undefined, - ...(parseFromValuesOrFunc(toolbarProps?.sx, theme)), + position: isFullScreen ? "sticky" : "relative", + top: isFullScreen ? "0" : undefined, + ...parseFromValuesOrFunc(toolbarProps?.sx, theme), })} > {renderTopToolbarCustomActions?.({ table }) ?? } {enableToolbarInternalActions && ( + + )} - {enablePagination && - ['both', 'top'].includes(positionPagination ?? '') && ( - - )} + {enablePagination && ["both", "top"].includes(positionPagination ?? "") && ( + + )} ); -} +}; -export default DataTable_TopToolbar \ No newline at end of file +export default DataTable_TopToolbar; diff --git a/src/core/components/NotificationDesign/AskForKeep.jsx b/src/core/components/NotificationDesign/AskForKeep.jsx new file mode 100644 index 0000000..d4721bb --- /dev/null +++ b/src/core/components/NotificationDesign/AskForKeep.jsx @@ -0,0 +1,61 @@ +"use client"; + +import SaveIcon from "@mui/icons-material/Save"; +import { Box, Button, Typography } from "@mui/material"; +import DownloadIcon from "@mui/icons-material/Download"; +import { toast } from "react-toastify"; + +function AskForKeep({ onSaveFilter }) { + const handleDismiss = () => { + toast.dismiss({ containerId: "filtering" }); + }; + + return ( + + + + ذخیره سازی اطلاعات + + + + + آیا مایل به ذخیره فیلتر های اعمال شده برای دفعات بعد هستید؟ + + + + + + + ); +} + +export default AskForKeep; diff --git a/src/core/components/SidebarListItems.jsx b/src/core/components/SidebarListItems.jsx index 9ffcac2..050d9a6 100644 --- a/src/core/components/SidebarListItems.jsx +++ b/src/core/components/SidebarListItems.jsx @@ -1,19 +1,22 @@ -import {Collapse, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; -import { ExpandLess, ExpandMore } from '@mui/icons-material'; -import WifiIcon from '@mui/icons-material/Wifi'; import SidebarSubitems from "@/core/components/SidebarSubitems"; +import { ExpandLess, ExpandMore } from "@mui/icons-material"; +import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from "@mui/material"; +import Link from "next/link"; -const SidebarListItems = ({menuItem, dispatch}) => { - return( +const SidebarListItems = ({ menuItem, dispatch }) => { + return ( <> - - { - dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) - }}> + + { + dispatch({ type: "COLLAPSE_MENU", id: menuItem.id }); + }} + > { color: "primary.main", width: 40, height: 24, - pr: 2, }} > {menuItem.icon} - - {menuItem.hasSubitems ? (menuItem.showSubitems ? : ) : null } + + {menuItem.hasSubitems ? menuItem.showSubitems ? : : null} - { - menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ - return( - - ) - })) : null - } + {menuItem.hasSubitems ? ( + + {menuItem.Subitems.map((subitem, index) => { + return ; + })} + + ) : null} - - ) -} -export default SidebarListItems \ No newline at end of file + ); +}; +export default SidebarListItems; diff --git a/src/core/components/SidebarMenu.jsx b/src/core/components/SidebarMenu.jsx index f7589c3..326dd11 100644 --- a/src/core/components/SidebarMenu.jsx +++ b/src/core/components/SidebarMenu.jsx @@ -1,170 +1,101 @@ -"use client" -import {List} from "@mui/material"; +"use client"; import SidebarListItems from "@/core/components/SidebarListItems"; -import {useEffect, useReducer, useState} from "react"; -import {usePathname} from 'next/navigation' -import SecurityIcon from '@mui/icons-material/Security'; -import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; -import AssessmentIcon from '@mui/icons-material/Assessment'; -import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; -import RepartitionIcon from '@mui/icons-material/Repartition'; - -const data = [ - { - id: "hello", - type: "menu", - route: "/hello", - icon: , - selected: false, - Subitems: [ - { - id: "amin", - route: "/s", - icon: , - firstName: "amin", - lastName: "ali", - Subitems: [ - { - id: "shahrokh", shahrokh: "shahrokh", type: "page", selected: false, route: "/dashbssoard", icon: - }, - { - id: "shasdasdsahrokh", shahrokh: "shahroasdasdkh", type: "page", selected: false, route: "/dashboardsd", icon: - } - ], - hasSubitems: true, - showSubitems: false, - type: "menu", - selected: false, - }, - { - id: "amir", - route: "/dashboarsad", - icon: , - firstName: "amir", - lastName: "akbar", - hasSubitems: false, - showSubitems: false, - selected: false, - type: "page", - }, - ], - hasSubitems: true, - showSubitems: false - }, - { - id: "hi", - type: "menu", - icon: , - route: "/hi", - selected: false, - Subitems: [ - { - id: "ali", - route: "/dashboardss", - firstName: "ali", - lastName: "ali", - icon: , - hasSubitems: false, - showSubitems: false, - type: "page", - selected: false, - }, - { - id: "akbar", - route: "/akbar", - firstName: "akbar", - icon: , - lastName: "akbar", - hasSubitems: false, - showSubitems: false, - type: "page", - selected: false, - }, - ], - hasSubitems: true, - showSubitems: false - }, - { - id: "hoo", - type: "page", - route: "/dashboard", - icon: , - selected: false, - hasSubitems: false, - showSubitems: false - } -] +import { usePermissions } from "@/lib/hooks/usePermissions"; +import { List } from "@mui/material"; +import { usePathname } from "next/navigation"; +import { useEffect, useReducer, useState } from "react"; +import { filterMenuItems } from "../utils/filterMenuItems"; +import { pageMenu } from "../utils/pageMenu"; function reducer(state, action) { switch (action.type) { + case "UPDATE_MENU": + const _permissions = action.permissions || [] + const filteredPageMenu = filterMenuItems(pageMenu, ['all', ..._permissions]) + return filteredPageMenu case "COLLAPSE_MENU": - return state.map((item) => action.id == item.id ? { - ...item, showSubitems: !item.showSubitems - } : item) - case "COLLAPSE_SUB_ITEMS" : + return state.map((item) => + action.id == item.id + ? { + ...item, + showSubitems: !item.showSubitems, + } + : item + ); + case "COLLAPSE_SUB_ITEMS": return state.map((item) => { - return item.hasSubitems ? { - ...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { - ...subitem, showSubitems: !subitem.showSubitems - } : subitem) - } : item - }) - case "COLLAPSE_SUB_SECOND_ITEMS" : + return item.hasSubitems + ? { + ...item, + Subitems: item.Subitems.map((subitem) => + action.id === subitem.id + ? { + ...subitem, + showSubitems: !subitem.showSubitems, + } + : subitem + ), + } + : item; + }); + case "COLLAPSE_SUB_SECOND_ITEMS": return state.map((item) => { - return item.hasSubitems ? { - ...item, Subitems: item.Subitems.map((subitem) => { - return subitem.hasSubitems ? { - ...subitem, - Subitems: subitem.Subitems.map((secondSubitem) => action.id === secondSubitem.id ? { - ...secondSubitem, showSubitems: !secondSubitem.showSubitems - } : secondSubitem) - } : subitem - }) - } : item - }) + return item.hasSubitems + ? { + ...item, + Subitems: item.Subitems.map((subitem) => { + return subitem.hasSubitems + ? { + ...subitem, + Subitems: subitem.Subitems.map((secondSubitem) => + action.id === secondSubitem.id + ? { + ...secondSubitem, + showSubitems: !secondSubitem.showSubitems, + } + : secondSubitem + ), + } + : subitem; + }), + } + : item; + }); case "SELECTED": return state.map((item) => { - return item.type === "page" ? { - ...item, selected: action.route === item.route,showSubitems: item.route === action.route - } : item.Subitems && Array.isArray(item.Subitems) ? { - ...item, Subitems: item.Subitems.map((subitem) => { - return subitem.type === "page" ? { - ...subitem, selected: action.route === subitem.route,showSubitems: subitem.route === action.route - } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { - ...subitem, Subitems: subitem.Subitems.map((secondSubItem) => ({ - ...secondSubItem, selected: secondSubItem.route === action.route - })),showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), - } : subitem - }),showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), - } : item + return item.type === "page" + ? { + ...item, + selected: action.route === item.route, + showSubitems: item.route === action.route, + } + : item.Subitems && Array.isArray(item.Subitems) + ? { + ...item, + Subitems: item.Subitems.map((subitem) => { + return subitem.type === "page" + ? { + ...subitem, + selected: action.route === subitem.route, + showSubitems: subitem.route === action.route, + } + : subitem.Subitems && Array.isArray(subitem.Subitems) + ? { + ...subitem, + Subitems: subitem.Subitems.map((secondSubItem) => ({ + ...secondSubItem, + selected: secondSubItem.route === action.route, + })), + showSubitems: subitem.Subitems.some( + (secondSubItem) => secondSubItem.route === action.route + ), + } + : subitem; + }), + showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), + } + : item; }); - // case "SELECTED": - // return state.map((item) => { - // return item.type === "page" ? { - // ...item, - // selected: action.route === item.route - // } : item.Subitems && Array.isArray(item.Subitems) ? { - // ...item, - // Subitems: item.Subitems.map((subitem) => { - // const updatedSubitem = subitem.type === "page" ? { - // ...subitem, - // selected: action.route === subitem.route - // } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { - // ...subitem, - // Subitems: subitem.Subitems.map((secondSubItem) => ({ - // ...secondSubItem, - // selected: secondSubItem.route === action.route - // })), - // showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), - // } : subitem; - // - // console.log("Updated subitem:", updatedSubitem); // Log the updated subitem - // return updatedSubitem; - // }), - // showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), - // } : item - // }); - default: throw new Error(); @@ -172,30 +103,34 @@ function reducer(state, action) { } const SidebarMenu = () => { - const [menuItems, dispatch] = useReducer(reducer, data); - const pathname = usePathname() + const { data: userPermissions } = usePermissions() + const [menuItems, dispatch] = useReducer(reducer, pageMenu); + const pathname = usePathname(); const [selectedKey, setSelectedKey] = useState(null); + useEffect(() => { - dispatch({type: "SELECTED", route: pathname}); + dispatch({ type: 'UPDATE_MENU', permissions: userPermissions }); + }, [userPermissions]) + + useEffect(() => { + dispatch({ type: "SELECTED", route: pathname }); setSelectedKey(pathname); }, [pathname]); useEffect(() => { - selectedKey && document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({ - behavior: "smooth", block: "center" - }); + selectedKey && + document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({ + behavior: "smooth", + block: "center", + }); }, [selectedKey]); return ( - - { - menuItems.map((menuItem) => { - return ( - - ) - }) - } + + {menuItems.map((menuItem) => { + return ; + })} - ) -} -export default SidebarMenu \ No newline at end of file + ); +}; +export default SidebarMenu; diff --git a/src/core/components/SidebarSubitems.jsx b/src/core/components/SidebarSubitems.jsx index 275befb..69418ea 100644 --- a/src/core/components/SidebarSubitems.jsx +++ b/src/core/components/SidebarSubitems.jsx @@ -1,74 +1,51 @@ -import {Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; -import {ExpandLess, ExpandMore} from "@mui/icons-material"; +import { ExpandLess, ExpandMore } from "@mui/icons-material"; +import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from "@mui/material"; +import Link from "next/link"; -const SidebarSubitems = ({subitem, dispatch}) => { +const SidebarSubitems = ({ subitem, dispatch }) => { return ( <> - - - { - dispatch({type: "COLLAPSE_SUB_ITEMS", id: subitem.id}) - }}> - - {subitem.icon} - - - {subitem.hasSubitems ? (subitem.showSubitems ? : ) : null - } - - - - { - subitem.hasSubitems ? (subitem.Subitems.map((subSubitem, index) => { - return ( - - - - { - dispatch({type: "COLLAPSE_SUB_SECOND_ITEMS", id: subSubitem.id}) - }} - selected={subSubitem.selected} - sx={{ - '&.Mui-selected': { - backgroundColor: 'rgba(0, 0, 0, 0.05)', - }, - }} - > - - {subSubitem.icon} - - - - - - - ) - })) : null - } + + { + dispatch({ type: "COLLAPSE_SUB_ITEMS", id: subitem.id }); + }} + > + + {subitem.icon} + + + {subitem.hasSubitems ? subitem.showSubitems ? : : null} + + + + {subitem.hasSubitems ? ( + + {subitem.Subitems.map((subSubitem, index) => { + return ; + })} + + ) : null} + - ) -} -export default SidebarSubitems \ No newline at end of file + ); +}; +export default SidebarSubitems; diff --git a/src/core/components/Toasts/error.jsx b/src/core/components/Toasts/error.jsx new file mode 100644 index 0000000..e93138b --- /dev/null +++ b/src/core/components/Toasts/error.jsx @@ -0,0 +1,187 @@ +import { toast } from "react-toastify"; +import { Box, Typography } from "@mui/material"; +import { Dangerous } from "@mui/icons-material"; + +export const errorServerToast = (toastContainer) => + toast.error( + () => ( + + + + + {"The request failed due to an internal error."} + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 5000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); + +export const errorUnauthorizedToast = (toastContainer) => + toast.error( + () => ( + + + + + {"The user is not authorized to make the request."} + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); + +export const errorLogicToast = (message, toastContainer) => + toast.error( + () => ( + + + + + + {message || + "The request was well-formed but was unable to be followed due to semantic errors."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorValidationToast = (message, toastContainer) => + toast.error( + () => ( + + + + + + {message || + "The request was well-formed but was unable to be followed due to semantic errors."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorTooManyToast = (toastContainer) => + toast.error( + () => ( + + + + + + {"Too many requests have been sent within a given time span."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorClientToast = (toastContainer) => + toast.error( + () => ( + + + + + + { + "The API request is invalid or improperly formed. Consequently, the API server could not understand the request." + } + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); diff --git a/src/core/components/Toasts/success.jsx b/src/core/components/Toasts/success.jsx new file mode 100644 index 0000000..36023c6 --- /dev/null +++ b/src/core/components/Toasts/success.jsx @@ -0,0 +1,33 @@ +import { toast } from "react-toastify"; +import { Box, Typography } from "@mui/material"; +import { Beenhere } from "@mui/icons-material"; + +export const successToast = (toastContainer) => + toast.success( + () => ( + + + + + {"Your operation was successful"} + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); diff --git a/src/core/middlewares/withAuth.js b/src/core/middlewares/withAuth.js new file mode 100644 index 0000000..216b55b --- /dev/null +++ b/src/core/middlewares/withAuth.js @@ -0,0 +1,22 @@ +"use client"; +import { useAuth } from "@/lib/contexts/auth"; +import { usePathname, useRouter } from "next/navigation"; +import { useEffect } from "react"; + +function WithAuthMiddleware({ children }) { + const router = useRouter(); + const pathName = usePathname(); + const { isAuth, initAuthState } = useAuth(); + + useEffect(() => { + if (!initAuthState) return; + if (!isAuth) { + router.replace(`${process.env.NEXT_PUBLIC_API_URL}/login?_back=${encodeURIComponent(pathName)}`); + } + }, [isAuth, initAuthState]); + + if (!initAuthState || !isAuth) return null; + return <>{children}; +} + +export default WithAuthMiddleware; diff --git a/src/core/utils/cacheRtl.js b/src/core/utils/cacheRtl.js index bf8c809..1393e2e 100644 --- a/src/core/utils/cacheRtl.js +++ b/src/core/utils/cacheRtl.js @@ -1,16 +1,16 @@ -'use client' +"use client"; import createCache from "@emotion/cache"; -import {prefixer} from "stylis"; +import { prefixer } from "stylis"; import stylisRTLPlugin from "stylis-plugin-rtl"; -import {CacheProvider} from "@emotion/react"; +import { CacheProvider } from "@emotion/react"; const cache = createCache({ - key: 'mui-rtl', + key: "mui-rtl", stylisPlugins: [prefixer, stylisRTLPlugin], }); const cacheProviderRtl = (props) => { return {props.children}; -} +}; -export default cacheProviderRtl \ No newline at end of file +export default cacheProviderRtl; diff --git a/src/core/utils/errorResponse.js b/src/core/utils/errorResponse.js new file mode 100644 index 0000000..1802581 --- /dev/null +++ b/src/core/utils/errorResponse.js @@ -0,0 +1,60 @@ +"use client"; +import { toast } from "react-toastify"; +import { + errorClientToast, + errorLogicToast, + errorServerToast, + errorTooManyToast, + errorUnauthorizedToast, + errorValidationToast, +} from "@/core/components/toasts/error"; + +const isServerError = (status) => status >= 500 && status <= 599; +const isClientError = (status) => status >= 400 && status <= 499; + +const errorServer = (response, notification, toastContainer) => { + if (notification) errorServerToast(toastContainer); +}; + +const errorClient = (response, notification, toastContainer) => { + switch (response.status) { + case 401: + if (notification) errorUnauthorizedToast(toastContainer); + break; + case 422: + if ("type" in response.data) { + if (Array.isArray(response.data.message)) { + response.data.message.map((item) => { + if (notification) errorLogicToast(item, toastContainer); + }); + } else { + if (notification) errorLogicToast(response.data.message, toastContainer); + } + break; + } + if (notification) { + const errorsMap = Object.keys(response.data.errors); + const errorsArray = response.data.errors; + + errorsMap.map((item, index) => { + errorValidationToast(errorsArray[item][0], toastContainer); + }); + } + break; + case 429: + if (notification) errorTooManyToast(toastContainer); + break; + default: + if (notification) errorClientToast(toastContainer); + break; + } +}; + +export const errorResponse = (response, notification, toastContainer) => { + if (notification) toast.dismiss({ container: toastContainer }); + if (isServerError(response.status)) { + errorServer(response, notification, toastContainer); + } else if (isClientError(response.status)) { + errorClient(response, notification, toastContainer); + } +}; diff --git a/src/core/utils/filterMenuItems.js b/src/core/utils/filterMenuItems.js new file mode 100644 index 0000000..7bceeb5 --- /dev/null +++ b/src/core/utils/filterMenuItems.js @@ -0,0 +1,17 @@ +export function filterMenuItems(items, _permissions = []) { + return items.reduce((acc, item) => { + if (item.permissions) { + if (item.permissions.some(permission => _permissions.includes(permission))) { + acc.push(item); + } + } else if (item.hasSubitems) { + const filteredSubItems = filterMenuItems(item.Subitems, _permissions); + if (filteredSubItems.length > 0) { + acc.push({ ...item, Subitems: filteredSubItems }); + } + } else { + acc.push(item); + } + return acc; + }, []); +} \ No newline at end of file diff --git a/src/core/utils/flattenArrayOfObjects.js b/src/core/utils/flattenArrayOfObjects.js index 4dd4612..5b1564c 100644 --- a/src/core/utils/flattenArrayOfObjects.js +++ b/src/core/utils/flattenArrayOfObjects.js @@ -7,4 +7,4 @@ export const flattenArrayOfObjects = (array, key) => { } return acc; }, []); -}; \ No newline at end of file +}; diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js new file mode 100644 index 0000000..9750e63 --- /dev/null +++ b/src/core/utils/pageMenu.js @@ -0,0 +1,378 @@ +import { AirlineSeatReclineNormal, Assessment, Repartition, Security, SpaceDashboard } from "@mui/icons-material"; + +export const pageMenu = [ + { + id: "dashboard", + label: "پیشخوان", + type: "page", + route: "/dashboard", + icon: , + permissions: ["all"] + }, + { + id: "userManagement", + label: "مدیریت کاربران", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/user_management", + icon: , + permissions: ['full-user-management', 'limited-user-management'] + }, + { + id: "projectsManagment", + label: "پروژه های راهداری", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "projectsManagmentFinance", + label: "ثبت قرارداد و پروژه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/finance", + icon: , + permissions: ['show-contract', 'show-contract-province'], + }, + { + id: "projectsManagmentList", + label: "لیست پروژه ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/projects_list", + icon: , + permissions: ["all"] + }, + { + id: "projectsManagmentProposal", + label: "پروژه های پیشنهادی", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/proposal", + icon: , + permissions: ['show-proposal', 'show-proposal-province'] + }, + { + id: "projectsManagmentLawmaker", + label: "درخواست نمایندگان", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/lawmakers", + icon: , + permissions: ['show-lawmaker', 'show-lawmaker-province'] + }, + { + id: "projectsManagmentMap", + label: "پراکندگی بر روی نقشه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=rahdari_projects", + icon: , + permissions: ["all"] + }, + ], + }, + { + id: "roadItemManagment", + label: "فعالیت های روزانه", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadItemManagmentSupervisor", + label: "ارزیابی", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadItemManagmentSupervisorCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/supervisor/cartable", + permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province'] + }, + ], + }, + { + id: "roadItemManagmentOparation", + label: "عملیات", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadItemManagmentOparationCreate", + label: "ثبت فعالیت", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/create", + permissions: ['create-road-item'] + }, + { + id: "roadItemManagmentOparationCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/cartable", + permissions: ['create-road-item'] + }, + ], + }, + { + id: "roadItemManagmentMap", + label: "پراکندگی بر روی نقشه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_items", + icon: , + permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province', 'create-road-item'] + }, + { + id: "roadItemManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/report", + icon: , + permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province', 'create-road-item'] + }, + ], + }, + { + id: "roadPatrolManagment", + label: "گشت راهداری و ترابری", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadPatrolManagmentSupervisor", + label: "ارزیابی", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadPatrolManagmentSupervisorCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/road_patrols/supervisor/cartable", + permissions: ['show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province'] + }, + ], + }, + { + id: "roadPatrolManagmentOparation", + label: "عملیات", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadPatrolManagmentOparationCreate", + label: "ثبت اقدام", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/create", + permissions: ['add-road-patrol'] + }, + { + id: "roadPatrolManagmentOparationCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/cartable", + permissions: ['add-road-patrol'] + }, + ], + }, + { + id: "roadPatrolManagmentMap", + label: "پراکندگی بر روی نقشه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_patrols", + icon: , + permissions: ['add-road-patrol', 'show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province'] + }, + { + id: "roadPatrolManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/report", + icon: , + permissions: ['add-road-patrol', 'show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province'] + }, + ], + }, + { + id: "safetyAndPrivacyManagment", + label: "نگهداری حریم راه", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "safetyAndPrivacyManagmentOparation", + label: "عملیات", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "safetyAndPrivacyManagmentOparationCreate", + label: "ثبت فعالیت", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/safety_and_privacy/operator/first_step", + permissions: ['add-safety-and-privacy'] + }, + { + id: "safetyAndPrivacyManagmentOparationCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/operator/cartable", + permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province', 'show-safety-and-privacy-operator-cartable-edarate-shahri'] + }, + ], + }, + { + id: "safetyAndPrivacyManagmentMap", + label: "پراکندگی بر روی نقشه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=safety_and_privacy", + icon: , + permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province', + 'show-safety-and-privacy-operator-cartable-edarate-shahri', 'add-safety-and-privacy'] + }, + { + id: "safetyAndPrivacyManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/report", + icon: , + permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province', + 'show-safety-and-privacy-operator-cartable-edarate-shahri', 'add-safety-and-privacy'] + }, + ], + }, + { + id: "roadObservationsManagment", + label: "واکنش سریع", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadObservationsManagmentSupervisor", + label: "ارزیابی", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadObservationsManagmentSupervisorCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/supervisor/cartable", + permissions: ['supervise-fast-react', 'supervise-fast-react-province'] + }, + ], + }, + { + id: "roadObservationsManagmentList", + label: "رسیدگی به شکایات", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations", + icon: , + permissions: ['show-fast-react', 'show-fast-react-province', 'show-fast-react-edarate-shahri'] + }, + { + id: "roadObservationsManagmentOparation", + label: "عملیات", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "roadObservationsManagmentOparationCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/operator/cartable", + permissions: ['show-fast-react', 'show-fast-react-province', 'show-fast-react-edarate-shahri'] + }, + ], + }, + { + id: "roadObservationsManagmentMap", + label: "پراکندگی بر روی نقشه", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_observations", + icon: , + permissions: ["all"] + }, + { + id: "roadObservationsManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/report/index", + icon: , + permissions: ["all"] + }, + ], + }, + { + id: "winterCampManagment", + label: "قرارگاه زمستانی", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "winterCampManagmentBlocking", + label: "محور های انسدادی", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/winter_camp", + icon: , + permissions: ['show-camp', 'show-camp-province'] + }, + { + id: "winterCampManagmentFirstRing", + label: "محور های حلقه اول", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=camp", + icon: , + permissions: ['show-camp', 'show-camp-province'] + }, + { + id: "winterCampManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=campNew", + icon: , + permissions: ['show-camp', 'show-camp-province'] + }, + ], + }, + { + id: "receiptManagment", + label: "خسارات وارده بر ابنیه فنی و تاسیسات راه", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "receiptManagmentOparation", + label: "عملیات", + type: "menu", + icon: , + hasSubitems: true, + Subitems: [ + { + id: "receiptManagmentOparationCartable", + label: "کارتابل", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt", + permissions: ["all"] + }, + ], + }, + { + id: "receiptManagmentReport", + label: "گزارش ها", + type: "page", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt/report", + icon: , + permissions: ["all"] + }, + ], + }, +]; diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js new file mode 100644 index 0000000..81ac016 --- /dev/null +++ b/src/core/utils/routes.js @@ -0,0 +1,6 @@ +const api = process.env.NEXT_PUBLIC_API_URL; + +export const GET_USER_ROUTE = api + "/webapi/user/get-permission"; +export const GET_LOGIN_ROUTE = api + "/login_dev"; + +export const GET_PERMISSIONS_ROUTE = api + "/webapi/user/get-permission"; \ No newline at end of file diff --git a/src/core/utils/successRequest.js b/src/core/utils/successRequest.js new file mode 100644 index 0000000..d23776a --- /dev/null +++ b/src/core/utils/successRequest.js @@ -0,0 +1,10 @@ +"use client"; +import { toast } from "react-toastify"; +import { successToast } from "@/core/components/toasts/success"; + +export const successRequest = (notification, toastContainer) => { + if (notification) { + toast.dismiss({ container: toastContainer }); + successToast(toastContainer); + } +}; diff --git a/src/core/utils/theme.js b/src/core/utils/theme.js index 3abbb52..f32031b 100644 --- a/src/core/utils/theme.js +++ b/src/core/utils/theme.js @@ -1,12 +1,22 @@ -'use client' +"use client"; import { createTheme } from "@mui/material"; const theme = createTheme({ - direction: 'rtl', + direction: "rtl", typography: { fontFamily: `IRANSansFaNum, sans-serif`, - fontSize: 12 + fontSize: 12, + }, + palette: { + primary: { + main: "#2070af", + contrastText: "#fff", + }, + primary2: { + main: "#015688", + contrastText: "#fff", + }, }, }); -export default theme \ No newline at end of file +export default theme; diff --git a/src/core/utils/utils.js b/src/core/utils/utils.js index 98e0252..a0a320d 100644 --- a/src/core/utils/utils.js +++ b/src/core/utils/utils.js @@ -1,162 +1,120 @@ import { alpha, darken } from "@mui/material"; -export const parseCSSVarId = (id) => id.replace(/[^a-zA-Z0-9]/g, '_'); +export const parseCSSVarId = (id) => id.replace(/[^a-zA-Z0-9]/g, "_"); -export const parseFromValuesOrFunc = ( - fn, - arg -) => (fn instanceof Function ? fn(arg) : fn); +export const parseFromValuesOrFunc = (fn, arg) => (fn instanceof Function ? fn(arg) : fn); -export const getCommonToolbarStyles = ({ - table, -}) => ({ - alignItems: 'flex-start', - backgroundColor: table.options.mrtTheme.baseBackgroundColor, - display: 'grid', - flexWrap: 'wrap-reverse', - minHeight: '3.5rem', - overflow: 'hidden', - position: 'relative', - transition: 'all 150ms ease-in-out', - zIndex: 1, +export const getCommonToolbarStyles = ({ table }) => ({ + alignItems: "flex-start", + backgroundColor: table.options.mrtTheme.baseBackgroundColor, + display: "grid", + flexWrap: "wrap-reverse", + minHeight: "3.5rem", + overflow: "hidden", + position: "relative", + transition: "all 150ms ease-in-out", + zIndex: 1, }); -export const getCommonTooltipProps = ( - placement, -) => ({ - disableInteractive: true, - enterDelay: 500, - enterNextDelay: 500, - placement, +export const getCommonTooltipProps = (placement) => ({ + disableInteractive: true, + enterDelay: 500, + enterNextDelay: 500, + placement, }); export const flipIconStyles = (theme) => - theme.direction === 'rtl' - ? { style: { transform: 'scaleX(-1)' } } - : undefined; + theme.direction === "rtl" ? { style: { transform: "scaleX(-1)" } } : undefined; -export const getCommonPinnedCellStyles = ({ - column, - table, - theme, -}) => { - const { baseBackgroundColor } = table.options.mrtTheme; - const isPinned = column?.getIsPinned(); +export const getCommonPinnedCellStyles = ({ column, table, theme }) => { + const { baseBackgroundColor } = table.options.mrtTheme; + const isPinned = column?.getIsPinned(); - return { - '&[data-pinned="true"]': { - '&:before': { - backgroundColor: alpha( - darken( - baseBackgroundColor, - theme.palette.mode === 'dark' ? 0.05 : 0.01, - ), - 0.97, - ), - boxShadow: column - ? isPinned === 'left' && column.getIsLastColumn(isPinned) - ? `-4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` - : isPinned === 'right' && column.getIsFirstColumn(isPinned) - ? `4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` - : undefined - : undefined, - ...commonCellBeforeAfterStyles, - }, - }, - }; + return { + '&[data-pinned="true"]': { + "&:before": { + backgroundColor: alpha(darken(baseBackgroundColor, theme.palette.mode === "dark" ? 0.05 : 0.01), 0.97), + boxShadow: column + ? isPinned === "left" && column.getIsLastColumn(isPinned) + ? `-4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` + : isPinned === "right" && column.getIsFirstColumn(isPinned) + ? `4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` + : undefined + : undefined, + ...commonCellBeforeAfterStyles, + }, + }, + }; }; -export const getCommonMRTCellStyles = ({ - column, - header, - table, - tableCellProps, - theme, -}) => { - const { - getState, - options: { enableColumnVirtualization, layoutMode }, - } = table; - const { draggingColumn } = getState(); - const { columnDef } = column; - const { columnDefType } = columnDef; +export const getCommonMRTCellStyles = ({ column, header, table, tableCellProps, theme }) => { + const { + getState, + options: { enableColumnVirtualization, layoutMode }, + } = table; + const { draggingColumn } = getState(); + const { columnDef } = column; + const { columnDefType } = columnDef; - const isColumnPinned = - columnDef.columnDefType !== 'group' && column.getIsPinned(); + const isColumnPinned = columnDef.columnDefType !== "group" && column.getIsPinned(); - const widthStyles = { - minWidth: `max(calc(var(--${header ? 'header' : 'col'}-${parseCSSVarId( - header?.id ?? column.id, - )}-size) * 1px), ${columnDef.minSize ?? 30}px)`, - width: `calc(var(--${header ? 'header' : 'col'}-${parseCSSVarId( - header?.id ?? column.id, - )}-size) * 1px)`, - }; + const widthStyles = { + minWidth: `max(calc(var(--${header ? "header" : "col"}-${parseCSSVarId( + header?.id ?? column.id + )}-size) * 1px), ${columnDef.minSize ?? 30}px)`, + width: `calc(var(--${header ? "header" : "col"}-${parseCSSVarId(header?.id ?? column.id)}-size) * 1px)`, + }; - if (layoutMode === 'grid') { - widthStyles.flex = `${[0, false].includes(columnDef.grow) - ? 0 - : `var(--${header ? 'header' : 'col'}-${parseCSSVarId( - header?.id ?? column.id, - )}-size)` - } 0 auto`; - } else if (layoutMode === 'grid-no-grow') { - widthStyles.flex = `${+(columnDef.grow || 0)} 0 auto`; - } - - const pinnedStyles = isColumnPinned - ? { - ...getCommonPinnedCellStyles({ column, table, theme }), - left: - isColumnPinned === 'left' - ? `${column.getStart('left')}px` - : undefined, - opacity: 0.97, - position: 'sticky', - right: - isColumnPinned === 'right' - ? `${column.getAfter('right')}px` - : undefined, + if (layoutMode === "grid") { + widthStyles.flex = `${ + [0, false].includes(columnDef.grow) + ? 0 + : `var(--${header ? "header" : "col"}-${parseCSSVarId(header?.id ?? column.id)}-size)` + } 0 auto`; + } else if (layoutMode === "grid-no-grow") { + widthStyles.flex = `${+(columnDef.grow || 0)} 0 auto`; } - : {}; - return { - backgroundColor: 'inherit', - backgroundImage: 'inherit', - display: layoutMode?.startsWith('grid') ? 'flex' : undefined, - justifyContent: - columnDefType === 'group' - ? 'center' - : layoutMode?.startsWith('grid') - ? tableCellProps.align - : undefined, - opacity: - table.getState().draggingColumn?.id === column.id || - table.getState().hoveredColumn?.id === column.id - ? 0.5 - : 1, - position: 'relative', - transition: enableColumnVirtualization - ? 'none' - : `padding 150ms ease-in-out`, - zIndex: - column.getIsResizing() || draggingColumn?.id === column.id - ? 2 - : columnDefType !== 'group' && isColumnPinned - ? 1 - : 0, - ...pinnedStyles, - ...widthStyles, - ...(parseFromValuesOrFunc(tableCellProps?.sx, theme)), - }; + const pinnedStyles = isColumnPinned + ? { + ...getCommonPinnedCellStyles({ column, table, theme }), + left: isColumnPinned === "left" ? `${column.getStart("left")}px` : undefined, + opacity: 0.97, + position: "sticky", + right: isColumnPinned === "right" ? `${column.getAfter("right")}px` : undefined, + } + : {}; + + return { + backgroundColor: "inherit", + backgroundImage: "inherit", + display: layoutMode?.startsWith("grid") ? "flex" : undefined, + justifyContent: + columnDefType === "group" ? "center" : layoutMode?.startsWith("grid") ? tableCellProps.align : undefined, + opacity: + table.getState().draggingColumn?.id === column.id || table.getState().hoveredColumn?.id === column.id + ? 0.5 + : 1, + position: "relative", + transition: enableColumnVirtualization ? "none" : `padding 150ms ease-in-out`, + zIndex: + column.getIsResizing() || draggingColumn?.id === column.id + ? 2 + : columnDefType !== "group" && isColumnPinned + ? 1 + : 0, + ...pinnedStyles, + ...widthStyles, + ...parseFromValuesOrFunc(tableCellProps?.sx, theme), + }; }; export const commonCellBeforeAfterStyles = { - content: '""', - height: '100%', - left: 0, - position: 'absolute', - top: 0, - width: '100%', - zIndex: -1, -}; \ No newline at end of file + content: '""', + height: "100%", + left: 0, + position: "absolute", + top: 0, + width: "100%", + zIndex: -1, +}; diff --git a/src/lib/contexts/DataTable.js b/src/lib/contexts/DataTable.js new file mode 100644 index 0000000..fb03fd7 --- /dev/null +++ b/src/lib/contexts/DataTable.js @@ -0,0 +1,11 @@ +import { createContext, useState } from "react"; + +export const DataTableContext = createContext(); + +const DataTableProvider = ({ children }) => { + const [filterData, setFilterData] = useState({}); + + return {children}; +}; + +export default DataTableProvider; diff --git a/src/lib/contexts/auth.js b/src/lib/contexts/auth.js new file mode 100644 index 0000000..f2df0e6 --- /dev/null +++ b/src/lib/contexts/auth.js @@ -0,0 +1,82 @@ +"use client"; +import { createContext, useCallback, useContext, useEffect, useReducer } from "react"; +import useRequest from "../hooks/useRequest"; +import { GET_USER_ROUTE } from "@/core/utils/routes"; + +const initAuth = { + initAuthState: false, + isAuth: false, + user: {}, +}; + +const authReducer = (state, action) => { + switch (action.type) { + case "CLEAR_USER": + return { ...state, user: {} }; + case "CHANGE_USER": + return { ...state, user: action.user }; + case "CHANGE_AUTH_STATE": + return { ...state, isAuth: action.isAuth }; + case "CHANGE_INIT_AUTH": + return { ...state, initAuthState: action.initAuthState }; + default: + return state; + } +}; + +const AuthContext = createContext(); + +export const AuthProvider = ({ children }) => { + const [state, dispatch] = useReducer(authReducer, initAuth); + const request = useRequest(); + + const clearUser = useCallback(() => { + dispatch({ type: "CLEAR_USER" }); + }, []); + + const changeUser = useCallback((user) => { + dispatch({ type: "CHANGE_USER", user }); + }, []); + + const changeAuthState = useCallback((isAuth) => { + dispatch({ type: "CHANGE_AUTH_STATE", isAuth }); + }, []); + + const changeInitAuth = useCallback((initAuthState) => { + dispatch({ type: "CHANGE_INIT_AUTH", initAuthState }); + }, []); + + const getUser = useCallback(async () => { + try { + const { data } = await request(GET_USER_ROUTE, "get"); + changeUser(data); + changeAuthState(true); + changeInitAuth(true); + } catch (error) { + if (error.response && error.response.status === 401) { + clearUser(); + changeAuthState(false); + changeInitAuth(true); + } + } + }, [clearUser, changeUser, changeAuthState, changeInitAuth]); + + useEffect(() => { + getUser(); + }, []); + + return ( + + {children} + + ); +}; + +export const useAuth = () => useContext(AuthContext); diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.js similarity index 55% rename from src/lib/contexts/tableSetting.jsx rename to src/lib/contexts/tableSetting.js index 0c2262d..3611df9 100644 --- a/src/lib/contexts/tableSetting.jsx +++ b/src/lib/contexts/tableSetting.js @@ -1,27 +1,26 @@ -'use client' -import {createContext, useCallback, useEffect, useState} from "react"; -import {flattenArrayOfObjects} from "@/core/utils/flattenArrayOfObjects"; +"use client"; +import { createContext, useCallback, useEffect, useState } from "react"; export const TableSettingContext = createContext(); -export const TableSettingProvider = ({children}) => { +export const TableSettingProvider = ({ children }) => { const [settingStore, setSettingStore] = useState({}); useEffect(() => { - const _localStorage = localStorage.getItem("_setting-app") + const _localStorage = localStorage.getItem("_setting-app"); if (_localStorage) { - setSettingStore(JSON.parse(_localStorage)) + setSettingStore(JSON.parse(_localStorage)); } }, []); const hideAction = useCallback((user_id, page_name, table_name, settingValue, columns) => { updateSettingStorage(user_id, page_name, table_name, "hides", settingValue, columns); - }, []) + }, []); const sortAction = useCallback((user_id, page_name, table_name, settingValue, columns) => { updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue, columns); - }, []) + }, []); const filterAction = (user_id, page_name, table_name, settingValue, columns) => { updateSettingStorage(user_id, page_name, table_name, "filters", settingValue, columns); - } + }; const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue, columns) => { const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; const userSettings = prevLocalStorage[user_id] || {}; @@ -31,7 +30,7 @@ export const TableSettingProvider = ({children}) => { if (settingType === "sorts" || settingType === "filters") { newSettings = [...settingValue]; } else { - newSettings = {...tableSettings[settingType] || {}, ...settingValue}; + newSettings = { ...(tableSettings[settingType] || {}), ...settingValue }; } const updatedLocalStorage = { ...prevLocalStorage, @@ -41,19 +40,38 @@ export const TableSettingProvider = ({children}) => { ...pageSettings, [table_name]: { ...tableSettings, - [settingType]: Array.isArray(settingValue) ? [...newSettings] : {...newSettings}, - summary: SummaryTextMessage({ - ...tableSettings, - [settingType]: Array.isArray(settingValue) ? [...newSettings] : {...newSettings}, - }, columns) + [settingType]: Array.isArray(settingValue) ? [...newSettings] : { ...newSettings }, + summary: SummaryTextMessage( + { + ...tableSettings, + [settingType]: Array.isArray(settingValue) ? [...newSettings] : { ...newSettings }, + }, + columns + ), }, }, }, }; localStorage.setItem("_setting-app", JSON.stringify(updatedLocalStorage)); setSettingStore(updatedLocalStorage); - } - + }; + const refactorAction = (user_id, page_name, table_name) => { + const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; + const userSettings = prevLocalStorage[user_id] || {}; + const pageSettings = userSettings[page_name] || {}; + const refactorData = { + ...prevLocalStorage, + [user_id]: { + ...userSettings, + [page_name]: { + ...pageSettings, + [table_name]: {}, + }, + }, + }; + localStorage.setItem("_setting-app", JSON.stringify(refactorData)); + setSettingStore(refactorData); + }; const SummaryTextMessage = (values, columns) => { let SummaryText = ""; let HideText = ""; @@ -61,38 +79,35 @@ export const TableSettingProvider = ({children}) => { let SortText = ""; if (values.sorts && values.sorts.length > 0) { - const _list = [] + const _list = []; for (const sort of values.sorts) { - const _column = columns.find(column => column.id == sort.id) - if (_column) - _list.push(`${_column.header}` + `(${sort.desc ? "نزولی" : "صعودی"})`) + const _column = columns.find((column) => column.id == sort.id); + if (_column) _list.push(`${_column.header}` + `(${sort.desc ? "نزولی" : "صعودی"})`); } - if (_list.length > 0) - SortText = " مرتب شده بر اساس : " + _list.join(", ") + if (_list.length > 0) SortText = " مرتب شده بر اساس : " + _list.join(", "); } if (values.filters && values.filters.length > 0) { - const _list = [] + const _list = []; for (const filter of values.filters) { - const _column = columns.find(column => column.id == filter.id) - if (_column) - _list.push(`${_column.header}`) + const _column = columns.find((column) => column.id == filter.id); + if (_column) _list.push(`${_column.header}`); } - if (_list.length > 0) - FilterText = " فیلتر شده بر اساس : " + _list.join(", ") + if (_list.length > 0) FilterText = " فیلتر شده بر اساس : " + _list.join(", "); } if (values.hides) { - const hidesArray = Object.entries(values.hides).map((e) => ({id: e[0], value: e[1]})) + const hidesArray = Object.entries(values.hides).map((e) => ({ + id: e[0], + value: e[1], + })); if (hidesArray.length > 0) { - const _list = [] + const _list = []; for (const hide of hidesArray) { - if (hide.value) continue - const _column = columns.find(c => c.id == hide.id) - if (_column) - _list.push(_column.header) + if (hide.value) continue; + const _column = columns.find((c) => c.id == hide.id); + if (_column) _list.push(_column.header); } - if (_list.length > 0) - HideText = "ستون های مخفی شده : " + _list.join(", "); + if (_list.length > 0) HideText = "ستون های مخفی شده : " + _list.join(", "); } } @@ -113,7 +128,7 @@ export const TableSettingProvider = ({children}) => { } } if (FilterText) { - SummaryText += FilterText + SummaryText += FilterText; } } @@ -122,8 +137,15 @@ export const TableSettingProvider = ({children}) => { return ( + value={{ + settingStore, + hideAction, + sortAction, + filterAction, + refactorAction, + }} + > {children} ); -}; \ No newline at end of file +}; diff --git a/src/lib/hooks/useDataTable.js b/src/lib/hooks/useDataTable.js new file mode 100644 index 0000000..e396908 --- /dev/null +++ b/src/lib/hooks/useDataTable.js @@ -0,0 +1,9 @@ +import { useContext } from "react"; +import { DataTableContext } from "@/lib/contexts/DataTable"; + +const useTableSetting = () => { + const { filterData, setFilterData } = useContext(DataTableContext); + return { filterData, setFilterData }; +}; + +export default useTableSetting; diff --git a/src/lib/hooks/usePermissions.js b/src/lib/hooks/usePermissions.js new file mode 100644 index 0000000..4f54b41 --- /dev/null +++ b/src/lib/hooks/usePermissions.js @@ -0,0 +1,18 @@ +import { GET_PERMISSIONS_ROUTE } from "@/core/utils/routes"; +import useSWR from "swr"; +import useRequest from "./useRequest"; + +export const usePermissions = () => { + const request = useRequest() + + const fetcher = async (url) => { + try { + const response = await request(url) + return response.data.data + } catch (error) { + throw new Error(); + } + }; + + return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true }); +} \ No newline at end of file diff --git a/src/lib/hooks/useRequest.js b/src/lib/hooks/useRequest.js new file mode 100644 index 0000000..2e35512 --- /dev/null +++ b/src/lib/hooks/useRequest.js @@ -0,0 +1,46 @@ +import { errorResponse } from "@/core/utils/errorResponse"; +import { successRequest } from "@/core/utils/successRequest"; +import axios from "axios"; + +const defaultOptions = { + data: {}, + requestOptions: { + headers: {}, + }, + notification: { + show: true, + success: false, + failed: true, + }, +}; + +const useRequest = (initOptions) => { + const _options = Object.assign({}, defaultOptions, initOptions); + + return async (url = "", method = "get", options) => { + const mergedOptions = Object.assign({}, _options, options); + + try { + const response = await axios({ + url, + method, + data: method === "get" ? null : mergedOptions.data, + withCredentials: true, + ...mergedOptions.requestOptions, + }); + successRequest(mergedOptions.notification.show && mergedOptions.notification.success, "request_data"); + return response; + } catch (error) { + if (error.response) { + errorResponse( + error.response, + mergedOptions.notification.show && mergedOptions.notification.failed, + "request_data" + ); + } + throw error; + } + }; +}; + +export default useRequest; diff --git a/src/lib/hooks/useTableSetting.js b/src/lib/hooks/useTableSetting.js new file mode 100644 index 0000000..6588446 --- /dev/null +++ b/src/lib/hooks/useTableSetting.js @@ -0,0 +1,9 @@ +import { useContext } from "react"; +import { TableSettingContext } from "../contexts/tableSetting"; + +const useTableSetting = () => { + const { settingStore, hideAction, sortAction, filterAction, refactorAction } = useContext(TableSettingContext); + return { settingStore, hideAction, sortAction, filterAction, refactorAction }; +}; + +export default useTableSetting; diff --git a/src/lib/hooks/useTableSetting.jsx b/src/lib/hooks/useTableSetting.jsx deleted file mode 100644 index 14d9d4e..0000000 --- a/src/lib/hooks/useTableSetting.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import { useContext } from "react"; -import { TableSettingContext } from "../contexts/tableSetting"; - -const useTableSetting = () => { - const { settingStore, hideAction, sortAction, filterAction } = - useContext(TableSettingContext); - return { settingStore, hideAction, sortAction, filterAction }; -}; - -export default useTableSetting;