diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..05e5a39 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,485 @@ +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/.gitignore b/.gitignore index e9618a3..78b977c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules .next -.env.local \ No newline at end of file +.env.local +.idea +package-lock.json \ No newline at end of file diff --git a/example.env.local b/example.env.local index 2b26da5..2c06285 100644 --- a/example.env.local +++ b/example.env.local @@ -1,9 +1,11 @@ NEXT_PUBLIC_API_NAME = "Loan Facilities Dashboard" +NEXT_PUBLIC_API_VERSION = "1.0.0" NEXT_PUBLIC_DEFAULT_LANGUAGE = "fa" NEXT_PUBLIC_DEFAULT_DIRECTION = "rtl" -NEXT_PUBLIC_API_URL = "http://Your IP:3000" +NEXT_PUBLIC_PRIMARY_MAIN = "#084070" +NEXT_PUBLIC_SECONDARY_MAIN = "#FF4E00" -NEXT_PUBLIC_BASE_URL = "deploy api" +NEXT_PUBLIC_BASE_URL = "https://loan.witel.ir" NODE_ENV = "development" \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json index f6a30b1..fcd02aa 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,8 +1,12 @@ { "compilerOptions": { "paths": { - "@/*": ["./src/*"], - "&/*": ["./public/*"], + "@/*": [ + "./src/*" + ], + "&/*": [ + "./public/*" + ] } } } diff --git a/next.config.js b/next.config.js index 03fb527..a288e34 100644 --- a/next.config.js +++ b/next.config.js @@ -1,12 +1,12 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - reactStrictMode: true, - i18n: { - defaultLocale: 'fa', - locales: ['fa'], - localeDetection: false, - }, + reactStrictMode: true, + i18n: { + defaultLocale: 'fa', + locales: ['fa'], + localeDetection: false, + } } module.exports = nextConfig diff --git a/package-lock.json b/package-lock.json index 2f1e600..42161b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,20 @@ "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.12.0", + "@mui/x-date-pickers": "^6.9.2", "axios": "^1.4.0", + "colord": "^2.9.3", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.11.9", "eslint": "8.36.0", "formik": "^2.2.9", "fs-extra": "^11.1.1", + "image-resize": "^1.3.2", + "image-to-file-converter": "^1.0.6", + "jalali-moment": "^3.3.11", "material-react-table": "^1.11.1", "moment": "^2.29.4", + "moment-jalaali": "^0.10.0", "next": "^13.3.0", "next-intl": "^2.13.1", "next-useragent": "^2.8.0", @@ -154,9 +162,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -729,13 +737,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.12.0.tgz", - "integrity": "sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw==", + "version": "5.13.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.7.tgz", + "integrity": "sha512-/3BLptG/q0u36eYED7Nhf4fKXmcKb6LjjT7ZMwhZIZSdSxVqDqSTmATW3a56n3KEPQUXCU9TpxAfCBQhs6brVA==", "dependencies": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.22.5", "@types/prop-types": "^15.7.5", - "@types/react-is": "^16.7.1 || ^17.0.0", + "@types/react-is": "^18.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -755,6 +763,71 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/@mui/x-date-pickers": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.9.2.tgz", + "integrity": "sha512-WoXRBUwb/nN/Hg+rArefkuRe30eVTN29dbjTN/vTydBFoNIp8vCaSeqRIEP6Zq2NaDHFWW9FMGChuuFEdROxWA==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@mui/utils": "^5.13.6", + "@types/react-transition-group": "^4.4.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/base": "^5.0.0-alpha.87", + "@mui/material": "^5.8.6", + "@mui/system": "^5.8.0", + "date-fns": "^2.25.0", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, "node_modules/@next/env": { "version": "13.3.0", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.0.tgz", @@ -1081,17 +1154,17 @@ } }, "node_modules/@types/react-is": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", - "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", + "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", "dependencies": { "@types/react": "*" } @@ -1236,6 +1309,31 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1431,6 +1529,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1439,6 +1556,56 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bl/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1459,6 +1626,29 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", @@ -1526,6 +1716,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1563,11 +1758,49 @@ "node": ">= 6" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -1592,6 +1825,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1603,6 +1841,14 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1665,6 +1911,16 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/date-fns-jalali": { + "version": "2.13.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-2.13.0-0.tgz", + "integrity": "sha512-yjlI9O18Z6ryGNagryrLO8OQ+3rishM3+A0UOX2UX10cWMn2NTlQcQ+ywTEJvF5IJz0FwX/slt2nCcpyQ/c8gw==" + }, + "node_modules/dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1722,6 +1978,17 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -2402,6 +2669,19 @@ "node": ">=0.10.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2453,6 +2733,28 @@ "reusify": "^1.0.4" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2894,6 +3196,36 @@ "html-tokenize": "bin/cmd.js" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2902,6 +3234,16 @@ "node": ">= 4" } }, + "node_modules/image-resize": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/image-resize/-/image-resize-1.3.2.tgz", + "integrity": "sha512-mbWBO4Fh+dsM5Nvj+ob01JE2gzla043PxilytGSMYUluOKEkVs1nhu2JwZ1dpRwwkYDkEOJENgm834LuunlIOQ==" + }, + "node_modules/image-to-file-converter": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/image-to-file-converter/-/image-to-file-converter-1.0.6.tgz", + "integrity": "sha512-CokQCAEtUHGOmc537r9yZHCi4UTxOnpUQ7JPcIGRjOntTEVlT7uNpmP1YuhUT/53ufEsxk9C+ReU23zhO/b+6Q==" + }, "node_modules/immutable": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", @@ -2944,6 +3286,31 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -3121,6 +3488,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3132,6 +3507,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -3270,6 +3653,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -3327,6 +3721,24 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/jalaali-js": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/jalaali-js/-/jalaali-js-1.2.6.tgz", + "integrity": "sha512-io974va+Qyu+UfuVX3UIAgJlxLhAMx9Y8VMfh+IG00Js7hXQo1qNQuwSiSa0xxco0SVgx5HWNkaiCcV+aZ8WPw==" + }, + "node_modules/jalali-moment": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/jalali-moment/-/jalali-moment-3.3.11.tgz", + "integrity": "sha512-tdSaRs9cjWjOIaWhcsGFZMhZQhfgok5J0TwqFpBIZPudZxxa6yjUPoLCOwuvbAtRpiZn7k/mvazAJh+vEN5suw==", + "dependencies": { + "commander": "^7.0.0", + "inquirer": "^8.0.0", + "moment": "^2.26.0" + }, + "bin": { + "jalalim": "cli.js" + } + }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -3464,6 +3876,21 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3554,6 +3981,14 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3581,6 +4016,28 @@ "node": "*" } }, + "node_modules/moment-jalaali": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/moment-jalaali/-/moment-jalaali-0.10.0.tgz", + "integrity": "sha512-XICH1+UHd3zyaE1bXWQBlhoXBqbzEyFfT0TrifNobHxLALRuTSwXn376bX8FmkYg9mZimevwwdd6EB57s5wuFA==", + "dependencies": { + "jalaali-js": "^1.1.0", + "moment": "^2.22.2", + "moment-timezone": "^0.5.21", + "rimraf": "^3.0.2" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3595,6 +4052,11 @@ "object-assign": "^4.1.0" } }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", @@ -3855,6 +4317,20 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -3888,6 +4364,36 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4218,6 +4724,18 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4241,6 +4759,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4263,6 +4789,14 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4282,6 +4816,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/sass": { "version": "1.62.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", @@ -4354,6 +4893,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4404,6 +4948,24 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -4617,6 +5179,17 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4806,6 +5379,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4879,6 +5460,22 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -5037,9 +5634,9 @@ } }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "requires": { "regenerator-runtime": "^0.13.11" } @@ -5425,13 +6022,13 @@ "requires": {} }, "@mui/utils": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.12.0.tgz", - "integrity": "sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw==", + "version": "5.13.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.7.tgz", + "integrity": "sha512-/3BLptG/q0u36eYED7Nhf4fKXmcKb6LjjT7ZMwhZIZSdSxVqDqSTmATW3a56n3KEPQUXCU9TpxAfCBQhs6brVA==", "requires": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.22.5", "@types/prop-types": "^15.7.5", - "@types/react-is": "^16.7.1 || ^17.0.0", + "@types/react-is": "^18.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -5443,6 +6040,19 @@ } } }, + "@mui/x-date-pickers": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.9.2.tgz", + "integrity": "sha512-WoXRBUwb/nN/Hg+rArefkuRe30eVTN29dbjTN/vTydBFoNIp8vCaSeqRIEP6Zq2NaDHFWW9FMGChuuFEdROxWA==", + "requires": { + "@babel/runtime": "^7.22.5", + "@mui/utils": "^5.13.6", + "@types/react-transition-group": "^4.4.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + } + }, "@next/env": { "version": "13.3.0", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.0.tgz", @@ -5633,17 +6243,17 @@ } }, "@types/react-is": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", - "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", + "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", "requires": { "@types/react": "*" } }, "@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", "requires": { "@types/react": "*" } @@ -5728,6 +6338,21 @@ "uri-js": "^4.2.2" } }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -5877,11 +6502,51 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5899,6 +6564,15 @@ "fill-range": "^7.0.1" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", @@ -5941,6 +6615,11 @@ "supports-color": "^7.1.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -5966,11 +6645,34 @@ } } }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==" + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, "client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, "clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -5989,6 +6691,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5997,6 +6704,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6050,6 +6762,16 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "date-fns-jalali": { + "version": "2.13.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-2.13.0-0.tgz", + "integrity": "sha512-yjlI9O18Z6ryGNagryrLO8OQ+3rishM3+A0UOX2UX10cWMn2NTlQcQ+ywTEJvF5IJz0FwX/slt2nCcpyQ/c8gw==" + }, + "dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6093,6 +6815,14 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -6626,6 +7356,16 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6673,6 +7413,21 @@ "reusify": "^1.0.4" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + } + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6984,11 +7739,34 @@ "through2": "~0.4.1" } }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" }, + "image-resize": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/image-resize/-/image-resize-1.3.2.tgz", + "integrity": "sha512-mbWBO4Fh+dsM5Nvj+ob01JE2gzla043PxilytGSMYUluOKEkVs1nhu2JwZ1dpRwwkYDkEOJENgm834LuunlIOQ==" + }, + "image-to-file-converter": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/image-to-file-converter/-/image-to-file-converter-1.0.6.tgz", + "integrity": "sha512-CokQCAEtUHGOmc537r9yZHCi4UTxOnpUQ7JPcIGRjOntTEVlT7uNpmP1YuhUT/53ufEsxk9C+ReU23zhO/b+6Q==" + }, "immutable": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", @@ -7022,6 +7800,28 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, "internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -7150,6 +7950,11 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -7158,6 +7963,11 @@ "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -7245,6 +8055,11 @@ "has-tostringtag": "^1.0.0" } }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -7290,6 +8105,21 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "jalaali-js": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/jalaali-js/-/jalaali-js-1.2.6.tgz", + "integrity": "sha512-io974va+Qyu+UfuVX3UIAgJlxLhAMx9Y8VMfh+IG00Js7hXQo1qNQuwSiSa0xxco0SVgx5HWNkaiCcV+aZ8WPw==" + }, + "jalali-moment": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/jalali-moment/-/jalali-moment-3.3.11.tgz", + "integrity": "sha512-tdSaRs9cjWjOIaWhcsGFZMhZQhfgok5J0TwqFpBIZPudZxxa6yjUPoLCOwuvbAtRpiZn7k/mvazAJh+vEN5suw==", + "requires": { + "commander": "^7.0.0", + "inquirer": "^8.0.0", + "moment": "^2.26.0" + } + }, "js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -7403,6 +8233,15 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7460,6 +8299,11 @@ "mime-db": "1.52.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7478,6 +8322,25 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, + "moment-jalaali": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/moment-jalaali/-/moment-jalaali-0.10.0.tgz", + "integrity": "sha512-XICH1+UHd3zyaE1bXWQBlhoXBqbzEyFfT0TrifNobHxLALRuTSwXn376bX8FmkYg9mZimevwwdd6EB57s5wuFA==", + "requires": { + "jalaali-js": "^1.1.0", + "moment": "^2.22.2", + "moment-timezone": "^0.5.21", + "rimraf": "^3.0.2" + } + }, + "moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "requires": { + "moment": "^2.29.4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7492,6 +8355,11 @@ "object-assign": "^4.1.0" } }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", @@ -7657,6 +8525,14 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, "open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -7681,6 +8557,27 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7909,6 +8806,15 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7922,6 +8828,11 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7930,6 +8841,14 @@ "queue-microtask": "^1.2.2" } }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7946,6 +8865,11 @@ "is-regex": "^1.1.4" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "sass": { "version": "1.62.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", @@ -7997,6 +8921,11 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8032,6 +8961,23 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + } + } + }, "string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -8186,6 +9132,14 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -8319,6 +9273,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8371,6 +9333,16 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index cbb68a7..86613ec 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,11 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "publish-3002": "next start -p 3002", + "lint": "next lint", + "update": "run-script-os", + "update:win32": "echo 'ok'", + "update:linux": "rm -rf .next/ && npm i && npm run build && sudo systemctl restart loan_facilities_develop_expert.service" }, "dependencies": { "@emotion/react": "^11.10.6", @@ -14,12 +18,20 @@ "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.12.0", + "@mui/x-date-pickers": "^6.9.2", "axios": "^1.4.0", + "colord": "^2.9.3", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.11.9", "eslint": "8.36.0", "formik": "^2.2.9", "fs-extra": "^11.1.1", + "image-resize": "^1.3.2", + "image-to-file-converter": "^1.0.6", + "jalali-moment": "^3.3.11", "material-react-table": "^1.11.1", "moment": "^2.29.4", + "moment-jalaali": "^0.10.0", "next": "^13.3.0", "next-intl": "^2.13.1", "next-useragent": "^2.8.0", @@ -36,6 +48,7 @@ }, "devDependencies": { "@faker-js/faker": "^7.6.0", - "eslint-config-next": "^13.3.0" + "eslint-config-next": "^13.3.0", + "run-script-os": "^1.1.6" } } diff --git a/public/fontiran.scss b/public/fontiran.scss index e263b42..86d585d 100644 --- a/public/fontiran.scss +++ b/public/fontiran.scss @@ -17,80 +17,153 @@ This set of fonts are used in this project under the license: (.....) * **/ @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: 900; - src: url('./fonts/eot/IRANSansWeb_Black.eot'); - src: url('./fonts/eot/IRANSansWeb_Black.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb_Black.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb_Black.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb_Black.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: 900; + src: url('./fonts/eot/IRANSansWeb(FaNum)_Black.eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum)_Black.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum)_Black.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum)_Black.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum)_Black.ttf') format('truetype'); } + @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: bold; - src: url('./fonts/eot/IRANSansWeb_Bold.eot'); - src: url('./fonts/eot/IRANSansWeb_Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb_Bold.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb_Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb_Bold.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: bold; + src: url('./fonts/eot/IRANSansWeb(FaNum)_Bold.eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum)_Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum)_Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf') format('truetype'); } + @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: 500; - src: url('./fonts/eot/IRANSansWeb_Medium.eot'); - src: url('./fonts/eot/IRANSansWeb_Medium.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb_Medium.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb_Medium.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb_Medium.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: 500; + src: url('./fonts/eot/IRANSansWeb(FaNum)_Medium.eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum)_Medium.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum)_Medium.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf') format('truetype'); } + @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: 300; - src: url('./fonts/eot/IRANSansWeb_Light.eot'); - src: url('./fonts/eot/IRANSansWeb_Light.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb_Light.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb_Light.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb_Light.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: 300; + src: url('./fonts/eot/IRANSansWeb(FaNum)_Light.eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum)_Light.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum)_Light.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum)_Light.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum)_Light.ttf') format('truetype'); } + @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: 200; - src: url('./fonts/eot/IRANSansWeb_UltraLight.eot'); - src: url('./fonts/eot/IRANSansWeb_UltraLight.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb_UltraLight.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb_UltraLight.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb_UltraLight.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: 200; + src: url('./fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf') format('truetype'); } + @font-face { - font-family: IRANSans; - font-style: normal; - font-weight: normal; - src: url('./fonts/eot/IRANSansWeb.eot'); - src: url('./fonts/eot/IRANSansWeb.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff2/IRANSansWeb.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ - url('./fonts/woff/IRANSansWeb.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/IRANSansWeb.ttf') format('truetype'); + font-family: IRANSansFaNum; + font-style: normal; + font-weight: normal; + src: url('./fonts/eot/IRANSansWeb(FaNum).eot'); + src: url('./fonts/eot/IRANSansWeb(FaNum).eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb(FaNum).woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb(FaNum).woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb(FaNum).ttf') format('truetype'); } + @font-face { - font-family: Parastoo; - font-style: normal; - font-weight: normal; - src: url('./fonts/eot/Parastoo.eot'); - src: url('./fonts/eot/Parastoo.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff/Parastoo.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/Parastoo.ttf') format('truetype'); + font-family: IRANSans; + font-style: normal; + font-weight: 900; + src: url('./fonts/eot/IRANSansWeb_Black.eot'); + src: url('./fonts/eot/IRANSansWeb_Black.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb_Black.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb_Black.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb_Black.ttf') format('truetype'); } + @font-face { - font-family: Parastoo; - font-style: normal; - font-weight: bold; - src: url('./fonts/eot/Parastoo-Bold.eot'); - src: url('./fonts/eot/Parastoo-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ - url('./fonts/woff/Parastoo-Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ - url('./fonts/ttf/Parastoo-Bold.ttf') format('truetype'); + font-family: IRANSans; + font-style: normal; + font-weight: bold; + src: url('./fonts/eot/IRANSansWeb_Bold.eot'); + src: url('./fonts/eot/IRANSansWeb_Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb_Bold.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb_Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb_Bold.ttf') format('truetype'); +} + +@font-face { + font-family: IRANSans; + font-style: normal; + font-weight: 500; + src: url('./fonts/eot/IRANSansWeb_Medium.eot'); + src: url('./fonts/eot/IRANSansWeb_Medium.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb_Medium.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb_Medium.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb_Medium.ttf') format('truetype'); +} + +@font-face { + font-family: IRANSans; + font-style: normal; + font-weight: 300; + src: url('./fonts/eot/IRANSansWeb_Light.eot'); + src: url('./fonts/eot/IRANSansWeb_Light.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb_Light.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb_Light.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb_Light.ttf') format('truetype'); +} + +@font-face { + font-family: IRANSans; + font-style: normal; + font-weight: 200; + src: url('./fonts/eot/IRANSansWeb_UltraLight.eot'); + src: url('./fonts/eot/IRANSansWeb_UltraLight.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb_UltraLight.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb_UltraLight.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb_UltraLight.ttf') format('truetype'); +} + +@font-face { + font-family: IRANSans; + font-style: normal; + font-weight: normal; + src: url('./fonts/eot/IRANSansWeb.eot'); + src: url('./fonts/eot/IRANSansWeb.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff2/IRANSansWeb.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/ + url('./fonts/woff/IRANSansWeb.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/IRANSansWeb.ttf') format('truetype'); +} + +@font-face { + font-family: Parastoo; + font-style: normal; + font-weight: normal; + src: url('./fonts/eot/Parastoo.eot'); + src: url('./fonts/eot/Parastoo.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff/Parastoo.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/Parastoo.ttf') format('truetype'); +} + +@font-face { + font-family: Parastoo; + font-style: normal; + font-weight: bold; + src: url('./fonts/eot/Parastoo-Bold.eot'); + src: url('./fonts/eot/Parastoo-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('./fonts/woff/Parastoo-Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('./fonts/ttf/Parastoo-Bold.ttf') format('truetype'); } diff --git a/public/fonts/eot/IRANSansWeb(FaNum).eot b/public/fonts/eot/IRANSansWeb(FaNum).eot new file mode 100644 index 0000000..5a6fdd0 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum).eot differ diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Black.eot b/public/fonts/eot/IRANSansWeb(FaNum)_Black.eot new file mode 100644 index 0000000..a012bc6 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum)_Black.eot differ diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot b/public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot new file mode 100644 index 0000000..82525e5 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot differ diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Light.eot b/public/fonts/eot/IRANSansWeb(FaNum)_Light.eot new file mode 100644 index 0000000..f899008 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum)_Light.eot differ diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot b/public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot new file mode 100644 index 0000000..117c2c8 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot differ diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot b/public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot new file mode 100644 index 0000000..9cd9b66 Binary files /dev/null and b/public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum).ttf b/public/fonts/ttf/IRANSansWeb(FaNum).ttf new file mode 100644 index 0000000..cd74265 Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum).ttf differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf b/public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf new file mode 100644 index 0000000..0f84dbf Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf b/public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf new file mode 100644 index 0000000..6fa2412 Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf b/public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf new file mode 100644 index 0000000..d9000c9 Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf b/public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf new file mode 100644 index 0000000..e20001c Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf differ diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf b/public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf new file mode 100644 index 0000000..0072606 Binary files /dev/null and b/public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum).woff b/public/fonts/woff/IRANSansWeb(FaNum).woff new file mode 100644 index 0000000..e34dfc4 Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum).woff differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Black.woff b/public/fonts/woff/IRANSansWeb(FaNum)_Black.woff new file mode 100644 index 0000000..bbbca77 Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum)_Black.woff differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff b/public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff new file mode 100644 index 0000000..05d933e Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Light.woff b/public/fonts/woff/IRANSansWeb(FaNum)_Light.woff new file mode 100644 index 0000000..fe80d47 Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum)_Light.woff differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff b/public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff new file mode 100644 index 0000000..f13a870 Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff differ diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff b/public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff new file mode 100644 index 0000000..9c653a4 Binary files /dev/null and b/public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum).woff2 b/public/fonts/woff2/IRANSansWeb(FaNum).woff2 new file mode 100644 index 0000000..30a377d Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum).woff2 differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2 b/public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2 new file mode 100644 index 0000000..0b15441 Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2 differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2 b/public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2 new file mode 100644 index 0000000..f2353b2 Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2 differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2 b/public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2 new file mode 100644 index 0000000..562d663 Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2 differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2 b/public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2 new file mode 100644 index 0000000..a69f4d0 Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2 differ diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2 b/public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2 new file mode 100644 index 0000000..1114f71 Binary files /dev/null and b/public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2 differ diff --git a/public/icons/favicon.png b/public/icons/favicon.png new file mode 100644 index 0000000..c82bf9a Binary files /dev/null and b/public/icons/favicon.png differ diff --git a/public/images/change-password.svg b/public/images/change-password.svg deleted file mode 100644 index f3b65aa..0000000 --- a/public/images/change-password.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/dashboard.svg b/public/images/dashboard.svg deleted file mode 100644 index ea3f11b..0000000 --- a/public/images/dashboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/login.svg b/public/images/login.svg deleted file mode 100644 index e2854d2..0000000 --- a/public/images/login.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/logo.svg b/public/images/logo.svg index 5931dd4..eebb9fa 100644 --- a/public/images/logo.svg +++ b/public/images/logo.svg @@ -1,10 +1,19 @@ - - - - - + + + + + + + + MARHABA + - MARHABA - diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 7d0f4ed..e78f16e 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -6,26 +6,59 @@ "login": "ورود", "login_expert": "ورود کارشناس", "expert": "کارشناس", + "last_updated_at": "اخرین بروز رسانی", + "filter_mode": "حالت فیلتر", + "date_picker_label": "فیلتر بر اساس تاریخ", + "lessThan": "کوچکتر از", + "greaterThan": "بزرگتر از", + "between": "میان", + "online_message": "شما به اینترنت وصل هستید", + "offline_message": "اتصال شما به اینترنت قطع شده است", "header": { "open_profile": "پروفایل", - "edit_profile": "ویرایش پروفایل", + "edit_profile": " پروفایل", "change_password": "تغییر رمز عبور", "logout": "خروج" }, "Titles": { "title_login_page": "صفحه ورود", - "title_login_expert_page": "ورود کارشناس" + "title_login_expert_page": "ورود کارشناس", + "title_custom_404": "صفحه یافت نشد", + "title_custom_403": "عدم دسترسی", + "title_custom_500": "خطای سرور" }, "sidebar": { - "dashboard": "داشبورد" + "dashboard": "داشبورد", + "passenger-office-chief": "اداره مسافر", + "machinery-expert": "ماشین آلات", + "passenger-boss": "رئیس مسافر ", + "transportation-assistant": "معاونت حمل و نقل", + "navgan-province-manager": "مدیر کل استانی", + "refahi-province-manager": "مدیر کل استانی", + "commercial-chief": "رئیس اداره بازرگانی", + "inspector-expert": "بازدید کارشناس", + "province-head-expert": "کارشناس ستادی", + "change-password": "تغییر رمز عبور", + "development-assistant": "معاون توسعه", + "edit-profile": "ویرایش پروفایل" + }, + "secondary": { + "passenger-office": "توزیع درخواست", + "passenger-boss": "کارگروه استانی", + "refahi-province-manager": "رفاهی", + "navgan-province-manager": "ناوگان" }, "Authorization": { "typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.", "typography_your_access_to_this_page_has_expired_Please_login_again": "دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.", - "typography_redirect_to": "رفتن به صفحه", + "typography_redirect_to": "درحال رفتن به صفحه", "typography_routing_previuos_page": "صفحه قبل...", "typography_routing_dashbaord_page": "داشبورد..." }, + "Permission": { + "typography_you_dont_have_access": "شما دسترسی لازم برای مشاهده این صفحه را ندارید!", + "button_back_dashboard": "بازگشت به صفحه اصلی" + }, "LoginPage": { "text_field_user_name": "نام کاربری", "text_field_enter_your_username": "نام کاربری خود را وارد کنید", @@ -35,10 +68,230 @@ "link_routing_back_to": "بازگشت به", "link_routing_previuos_page": "صفحه قبل", "link_routing_main_page": "صفحه اصلی", - "error_message_required": "اجباری!", - "button_make_account": "ایجاد حساب" + "error_message_required": "اجباری!" }, - "dashboard": { - "dashboard_page": "داشبورد" + "ErrorPage": { + "custom_404": "صفحه مورد نظر یافت نشد | 404", + "custom_500": "دسترسی به سامانه امکانپذیر نمی باشد دقایقی دیگر تلاش نمائید | 500", + "custom_403": "شما دسترسی به این بخش را ندارید | 403", + "link_routing_back_to": "بازگشت به", + "link_routing_previuos_page": "صفحه قبل", + "link_routing_main_page": "صفحه اصلی" + }, + "Dashboard": { + "dashboard_page": "داشبورد", + "passenger_boss_page": "رئیس مسافر", + "transportation_assistance": "معاونت حمل و نقل", + "change_password": "تغییر رمز عبور", + "province_manager_page": "مدیر کل استانی", + "province_head_expert": "کارشناس ستادی", + "passenger_office_page": "اداره مسافر", + "machinary_office_page": "ماشین آلات", + "development_assistant_page": "معاون توسعه", + "inspector_expert_page": "بازدید کارشناس", + "commercial_chief_page": "رئیس اداره بازرگانی", + "edit_profile": "ویرایش پروفایل" + }, + "MuiDatePicker": { + "date_picker_birthday": "تاریخ" + }, + "ChangePassword": { + "typography_change_password": "تغییر رمز عبور", + "label_current_password": "رمز عبور فعلی", + "label_new_password": "رمز عبور جدید", + "label_confirm_password": "تکرار رمز عبور جدید", + "error_message_required": "اجباری !", + "error_message_password_length": "رمز عبور باید حداقل 8 کاراکتر باشد.", + "error_message_password_match": "پسورد ها یکسان هستند", + "error_message_password_not_match": "پسورد و تکرار رمز عبور باید یکسان باشد" + }, + "SubmitButton": { + "button_while_submit": "در حال ثبت", + "button_submit": "ثبت" + }, + "UpdateProfile": { + "error_invalid_email": "ایمیل نامعتبر است", + "typography_edit_profile": "پروفایل", + "text_field_email": "ایمیل", + "text_field_enter_your_password": "رمز عبور خود را وارد کنید", + "text_field_username": "نام کاربری", + "text_field_name": "نام", + "text_field_phone_number": "شماره تماس", + "text_field_position": "سمت", + "text_field_province_name": "نام استان", + "error_message_required": "اجباری !" + }, + "notifications": { + "code": "کد", + "error": "خطا", + "warning": "خطا", + "success": "موفق", + "error_static_text": "عملیات شما با خطا مواجه شد", + "warning_static_text": "خطا سرور", + "success_static_text": "عملیات شما با موفقیت انجام شد", + "pending": "در حال انجام..." + }, + "PassengerOffice": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "CommercialChief": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "NavganProvinceManager": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "PassengerBoss": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "RefahiProvinceManager": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "DevelopmentAssistant": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "DevelopmentAssistant": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "ProvinceHeadExpert": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "TransportationAssistance": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "InspectorExpert": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "MachinaryOffice": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, + "ConfirmDialog": { + "confirm": "تایید", + "context": "آیا از تایید این آیتم اطمینان دارید؟", + "button-cancel": "بستن", + "button-confirm": "تایید", + "description_error": "وارد کردن توضیحات الزامی است!", + "optional": " (اختیاری)", + "unit": " (ریال)", + "description": "توضیحات خود را وارد نمائید", + "choose_file": "انتخاب فایل", + "approved_amount": "مبلغ تصویب شده", + "approved_amount_error": "وارد کردن مبلغ تصویب شده الزامیست", + "approved_amount_positive": "مبلغ تصویب شده باید مثبت باشد", + "proposed_amount_error": "وارد کردن مقدار پیشنهادی الزامیست", + "proposed_amount": "مقدار پیشنهادی", + "proposed_amount_positive": "مقدار پیشنهادی باید مثبت باشد" + }, + "ReviseDialog": { + "revise": "ویرایش", + "description_error": "وارد کردن توضیحات الزامی است!", + "optional": " (اختیاری)", + "button-cancel": "بستن", + "button-revise": "ویرایش", + "description": "توضیحات خود را وارد نمائید" + }, + "RejectDialog": { + "reject": "عدم تایید", + "context": "آیا از عدم تایید این آیتم اطمینان دارید؟", + "button-cancel": "بستن", + "button-reject": "عدم تایید", + "description": "توضیحات خود را وارد نمائید", + "optional": " (اختیاری)", + "description_error": "وارد کردن توضیحات الزامی است!" + }, + "UploadSystem": { + "upload_file": "فایل خود را بارگذاری کنید", + "optional": " (اختیاری)", + "upload_file_unit": "حداکثر 2Mb", + "upload_file_format": "فرمت قابل قبول : png,jpg,pdf", + "delete": "پاک کردن", + "uploadfile_error": "حجم فایل بیشتر از 2 مگابایت می باشد" } } diff --git a/public/locales/fa/datatable.js b/public/locales/fa/datatable.js index e42208f..fd43663 100644 --- a/public/locales/fa/datatable.js +++ b/public/locales/fa/datatable.js @@ -1,92 +1,92 @@ export const FA_DATATABLE_LOCALIZATION = { - actions: "Actions", - and: "and", - cancel: "Cancel", - changeFilterMode: "Change filter mode", - changeSearchMode: "Change search mode", - clearFilter: "Clear filter", - clearSearch: "Clear search", - clearSort: "Clear sort", - clickToCopy: "Click to copy", - collapse: "Collapse", - collapseAll: "Collapse all", - columnActions: "Column Actions", - copiedToClipboard: "Copied to clipboard", - dropToGroupBy: "Drop to group by {column}", - edit: "Edit", - expand: "Expand", - expandAll: "Expand all", - filterArrIncludes: "Includes", - filterArrIncludesAll: "Includes all", - filterArrIncludesSome: "Includes", - filterBetween: "Between", - filterBetweenInclusive: "Between Inclusive", - filterByColumn: "Filter by {column}", - filterContains: "Contains", - filterEmpty: "Empty", - filterEndsWith: "Ends With", - filterEquals: "Equals", - filterEqualsString: "Equals", - filterFuzzy: "Fuzzy", - filterGreaterThan: "Greater Than", - filterGreaterThanOrEqualTo: "Greater Than Or Equal To", - filterInNumberRange: "Between", - filterIncludesString: "Contains", - filterIncludesStringSensitive: "Contains", - filterLessThan: "Less Than", - filterLessThanOrEqualTo: "Less Than Or Equal To", - filterMode: "Filter Mode: {filterType}", - filterNotEmpty: "Not Empty", - filterNotEquals: "Not Equals", - filterStartsWith: "Starts With", - filterWeakEquals: "Equals", - filteringByColumn: "Filtering by {column} - {filterType} {filterValue}", - goToFirstPage: "Go to first page", - goToLastPage: "Go to last page", - goToNextPage: "Go to next page", - goToPreviousPage: "Go to previous page", - grab: "Grab", - groupByColumn: "Group by {column}", - groupedBy: "Grouped by ", - hideAll: "Hide all", - hideColumn: "Hide {column} column", - max: "Max", - min: "Min", - move: "Move", - noRecordsToDisplay: "No records to display", - noResultsFound: "No results found", - of: "of", - or: "or", - pinToLeft: "Pin to left", - pinToRight: "Pin to right", - resetColumnSize: "Reset column size", - resetOrder: "Reset order", - rowActions: "Row Actions", - rowNumber: "#", - rowNumbers: "Row Numbers", - rowsPerPage: "Rows per page", - save: "Save", - search: "Search", - selectedCountOfRowCountRowsSelected: - "{selectedCount} of {rowCount} row(s) selected", - select: "Select", - showAll: "Show all", - showAllColumns: "Show all columns", - showHideColumns: "Show/Hide columns", - showHideFilters: "Show/Hide filters", - showHideSearch: "Show/Hide search", - sortByColumnAsc: "Sort by {column} ascending", - sortByColumnDesc: "Sort by {column} descending", - sortedByColumnAsc: "Sorted by {column} ascending", - sortedByColumnDesc: "Sorted by {column} descending", - thenBy: ", then by ", - toggleDensity: "Toggle density", - toggleFullScreen: "Toggle full screen", - toggleSelectAll: "Toggle select all", - toggleSelectRow: "Toggle select row", - toggleVisibility: "Toggle visibility", - ungroupByColumn: "Ungroup by {column}", - unpin: "Unpin", - unpinAll: "Unpin all", - unsorted: "Unsorted", + actions: "عملیات", + and: "و", + cancel: "لغو", + changeFilterMode: "تغییر حالت فیلتر", + changeSearchMode: "تغییر حالت جستجو", + clearFilter: "پاک کردن فیلتر", + clearSearch: "پاک کردن جستجو", + clearSort: "پاک کردن مرتب سازی", + clickToCopy: "کلیک برای کپی", + collapse: "جمع شدن", + collapseAll: "جمع شدن همه", + columnActions: "عملیات ستون", + copiedToClipboard: "کپی شد", + dropToGroupBy: "رها کردن برای گروه بندی بر اساس {column}", + edit: "ویرایش", + expand: "باز شدن", + expandAll: "باز شدن همه", + filterArrIncludes: "شامل", + filterArrIncludesAll: "شامل همه", + filterArrIncludesSome: "شامل", + filterBetween: "میان", + filterBetweenInclusive: "میان با احتساب هر دو", + filterByColumn: "فیلتر بر اساس {column}", + filterContains: "شامل", + filterEmpty: "خالی", + filterEndsWith: "به پایان می‌رسد با", + filterEquals: "برابر", + filterEqualsString: "برابر", + filterFuzzy: "نزدیک", + filterGreaterThan: "بزرگتر از", + filterGreaterThanOrEqualTo: "بزرگتر یا مساوی", + filterInNumberRange: "میان", + filterIncludesString: "شامل", + filterIncludesStringSensitive: "شامل", + filterLessThan: "کوچکتر از", + filterLessThanOrEqualTo: "کوچکتر یا مساوی", + filterMode: "حالت فیلتر: {filterType}", + filterNotEmpty: "غیر خالی", + filterNotEquals: "نا برابر", + filterStartsWith: "شروع می‌شود با", + filterWeakEquals: "برابر", + filteringByColumn: "فیلتر بر اساس {column} - {filterType} {filterValue}", + goToFirstPage: "رفتن به صفحه اول", + goToLastPage: "رفتن به صفحه آخر", + goToNextPage: "رفتن به صفحه بعدی", + goToPreviousPage: "رفتن به صفحه قبلی", + grab: "گرفتن", + groupByColumn: "گروه بندی بر اساس {column}", + groupedBy: "گروه بندی شده بر اساس", + hideAll: "پنهان کردن همه", + hideColumn: "پنهان کردن ستون {column}", + max: "حداکثر", + min: "حداقل", + move: "انتقال", + noRecordsToDisplay: "هیچ رکوردی برای نمایش وجود ندارد", + noResultsFound: "نتیجه‌ای یافت نشد", + of: "از", + or: "یا", + pinToLeft: "چسباندن به سمت چپ", + pinToRight: "چسباندن به سمت راست", + resetColumnSize: "بازنشانی اندازه ستون", + resetOrder: "بازنشانی ترتیب", + rowActions: "عملیات ردیف", + rowNumber: "#", + rowNumbers: "شماره ردیف", + rowsPerPage: "ردیف در هر صفحه", + save: "ذخیره", + search: "جستجو", + selectedCountOfRowCountRowsSelected: + "{selectedCount} از {rowCount} ردیف انتخاب شده", + select: "انتخاب", + showAll: "نمایش همه", + showAllColumns: "نمایش همه ستون‌ها", + showHideColumns: "نمایش/مخفی کردن ستون‌ها", + showHideFilters: "نمایش/مخفی کردن فیلترها", + showHideSearch: "نمایش/مخفی کردن جستجو", + sortByColumnAsc: "مرتب سازی بر اساس {column} صعودی", + sortByColumnDesc: "مرتب سازی بر اساس {column} نزولی", + sortedByColumnAsc: "مرتب شده بر اساس {column} صعودی", + sortedByColumnDesc: "مرتب شده بر اساس {column} نزولی", + thenBy: "، سپس بر اساس ", + toggleDensity: "تغییر تراکم", + toggleFullScreen: "تغییر حالت تمام صفحه", + toggleSelectAll: "انتخاب/عدم انتخاب همه", + toggleSelectRow: "انتخاب/عدم انتخاب ردیف", + toggleVisibility: "تغییر پیدا/پنهان", + ungroupByColumn: "لغو گروه بندی بر اساس {column}", + unpin: "رها کردن", + unpinAll: "رها کردن همه", + unsorted: "بدون مرتب سازی", }; diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..6bc19ce --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,57 @@ +{ + "short_name": "Loan Facilities Dashboard", + "name": "Loan Facilities Expert Dashboard", + "description": "Loan Facilities", + "version": "1.0.0", + "version_name": "1.0.0 beta", + "start_url": "/dashboard", + "orientation": "portrait", + "display": "standalone", + "theme_color": "#084070", + "background_color": "#084070", + "icons": [ + { + "src": "/icons/maskable_icon.png", + "sizes": "any", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "/icons/maskable_icon_x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "categories": [ + "government" + ] +} diff --git a/src/components/dashboard/change-password/index.jsx b/src/components/dashboard/change-password/index.jsx new file mode 100644 index 0000000..ae74de6 --- /dev/null +++ b/src/components/dashboard/change-password/index.jsx @@ -0,0 +1,149 @@ +import CenterLayout from "@/layouts/CenterLayout"; +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Button, Container, Paper, Stack, Typography,} from "@mui/material"; +import {Formik} from "formik"; +import * as Yup from "yup"; +import {useTranslations} from "next-intl"; +import PasswordField from "@/core/components/PasswordField"; +import StyledForm from "@/core/components/StyledForm"; +import {SET_USER_PASSWORD} from "@/core/data/apiRoutes"; +import SvgChangePassword from "@/core/components/svgs/SvgChangePassword"; +import useRequest from "@/lib/app/hooks/useRequest"; + +const DashboardChangePasswordComponent = () => { + const t = useTranslations(); + const requestServer = useRequest({auth: true}) + + const handleSubmit = (values, {setSubmitting, resetForm}) => { + requestServer(SET_USER_PASSWORD, 'post', { + data: { + current_password: values.current_password, + new_password: values.new_password, + new_password_confirmation: values.new_password_confirmation, + }, + }).then((response) => { + resetForm(); + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }; + const initialValues = { + current_password: "", + new_password: "", + new_password_confirmation: "", + }; + const validationSchema = Yup.object().shape({ + current_password: Yup.string().required( + t("ChangePassword.error_message_required") + ), + new_password: Yup.string() + .min(8, t("ChangePassword.error_message_password_length")) + .required(t("ChangePassword.error_message_required")), + new_password_confirmation: Yup.string() + .required(t("ChangePassword.error_message_required")) + .test( + t("ChangePassword.error_message_password_match"), + t("ChangePassword.error_message_password_not_match"), + function (value) { + return this.parent.new_password === value; + } + ), + }); + + return ( + + + + + {(props) => ( + { + e.preventDefault(); + props.handleSubmit(); + }} + > + + + + + {t("ChangePassword.typography_change_password")} + + + + + + + + + + + + + + + )} + + + + + ); +}; +export default DashboardChangePasswordComponent; diff --git a/src/components/dashboard/commercial-chief/Form/ConfirmForm.jsx b/src/components/dashboard/commercial-chief/Form/ConfirmForm.jsx new file mode 100644 index 0000000..c2025ab --- /dev/null +++ b/src/components/dashboard/commercial-chief/Form/ConfirmForm.jsx @@ -0,0 +1,142 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_COMMERCIAL_CHIEF} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_COMMERCIAL_CHIEF}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/commercial-chief/Form/RejectForm.jsx b/src/components/dashboard/commercial-chief/Form/RejectForm.jsx new file mode 100644 index 0000000..fd8becb --- /dev/null +++ b/src/components/dashboard/commercial-chief/Form/RejectForm.jsx @@ -0,0 +1,146 @@ +import {REJECT_COMMERCIAL_CHIEF} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_COMMERCIAL_CHIEF}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/commercial-chief/TableRowActions.jsx b/src/components/dashboard/commercial-chief/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/commercial-chief/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/commercial-chief/TableTollbar.jsx b/src/components/dashboard/commercial-chief/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/commercial-chief/index.jsx b/src/components/dashboard/commercial-chief/index.jsx new file mode 100644 index 0000000..4ac03b3 --- /dev/null +++ b/src/components/dashboard/commercial-chief/index.jsx @@ -0,0 +1,201 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_COMMERCIAL_CHIEF} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardCommercialChiefComponent() { + const t = useTranslations(); + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("CommercialChief.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("CommercialChief.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("CommercialChief.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("CommercialChief.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("CommercialChief.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("CommercialChief.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("CommercialChief.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardCommercialChiefComponent; diff --git a/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx b/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx new file mode 100644 index 0000000..07b3253 --- /dev/null +++ b/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx @@ -0,0 +1,141 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_DEVELOPMENT_ASSISTANT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/development-assistant/Form/RejectForm.jsx b/src/components/dashboard/development-assistant/Form/RejectForm.jsx new file mode 100644 index 0000000..eb4e4a1 --- /dev/null +++ b/src/components/dashboard/development-assistant/Form/RejectForm.jsx @@ -0,0 +1,146 @@ +import {REJECT_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_DEVELOPMENT_ASSISTANT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/development-assistant/TableRowActions.jsx b/src/components/dashboard/development-assistant/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/development-assistant/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/development-assistant/TableTollbar.jsx b/src/components/dashboard/development-assistant/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/development-assistant/index.jsx b/src/components/dashboard/development-assistant/index.jsx new file mode 100644 index 0000000..e54daab --- /dev/null +++ b/src/components/dashboard/development-assistant/index.jsx @@ -0,0 +1,202 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardDevelopmentAssistantComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("DevelopmentAssistant.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("DevelopmentAssistant.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("DevelopmentAssistant.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("DevelopmentAssistant.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("DevelopmentAssistant.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("DevelopmentAssistant.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("DevelopmentAssistant.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardDevelopmentAssistantComponent; diff --git a/src/components/dashboard/edit-profile/index.jsx b/src/components/dashboard/edit-profile/index.jsx new file mode 100644 index 0000000..3018aa3 --- /dev/null +++ b/src/components/dashboard/edit-profile/index.jsx @@ -0,0 +1,223 @@ +import StyledForm from "@/core/components/StyledForm"; +import CenterLayout from "@/layouts/CenterLayout"; +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import useUser from "@/lib/app/hooks/useUser"; +import {Box, Container, Grid, Paper, Stack, TextField, Typography,} from "@mui/material"; +import * as Yup from "yup"; +import {Field, Formik} from "formik"; +import {useTranslations} from "next-intl"; +import AvatarUpload from "@/core/components/AvatarUpload"; +import axios from "axios"; +import {UPDATE_AVATAR} from "@/core/data/apiRoutes"; +import useDirection from "@/lib/app/hooks/useDirection"; +import Notifications from "@/core/components/notifications"; +import ImageResizer from "@/core/components/ImageConvertor"; + +const DashboardEditProfile = () => { + const t = useTranslations(); + const {user, token, getUser, changeUser} = useUser(); + const {directionApp} = useDirection(); + + const editAvatar = async (avatar) => { + Notifications(t); + try { + const formData = new FormData(); + + if (avatar != null) { + var resizedAvatar; + resizedAvatar = await ImageResizer(avatar); + formData.append("avatar", resizedAvatar); + } + + await axios.post(UPDATE_AVATAR, formData, { + headers: { + authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + }, + }); + } catch (error) { + Notifications(t, error.response); + throw error; + } + }; + const handleSubmit = (values, {setSubmitting}) => { + + }; + const initialValues = { + expert_avatar: null, + username: user.username, + name: user.name, + email: user.email, + province_name: user.province_name, + position: user.position, + }; + const validationSchema = Yup.object().shape({}); + + return ( + + + + + {(props) => ( + { + e.preventDefault(); + props.handleSubmit(); + }} + > + + + + {t("UpdateProfile.typography_edit_profile")} + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + + + + ); +}; + +export default DashboardEditProfile; diff --git a/src/components/dashboard/first/index.jsx b/src/components/dashboard/first/index.jsx index c693380..ee4f80a 100644 --- a/src/components/dashboard/first/index.jsx +++ b/src/components/dashboard/first/index.jsx @@ -1,7 +1,7 @@ import DashboardLayouts from "@/layouts/dashboardLayouts"; const DashboardFirstComponent = () => { - return ; + return ; }; export default DashboardFirstComponent; diff --git a/src/components/dashboard/inspector-expert/Form/ConfirmForm.jsx b/src/components/dashboard/inspector-expert/Form/ConfirmForm.jsx new file mode 100644 index 0000000..409ba94 --- /dev/null +++ b/src/components/dashboard/inspector-expert/Form/ConfirmForm.jsx @@ -0,0 +1,141 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_INSPECTOR_EXPERT} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_INSPECTOR_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/inspector-expert/Form/RejectForm.jsx b/src/components/dashboard/inspector-expert/Form/RejectForm.jsx new file mode 100644 index 0000000..f59758d --- /dev/null +++ b/src/components/dashboard/inspector-expert/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_INSPECTOR_EXPERT} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_INSPECTOR_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/inspector-expert/Form/ReviseForm.jsx b/src/components/dashboard/inspector-expert/Form/ReviseForm.jsx new file mode 100644 index 0000000..2661965 --- /dev/null +++ b/src/components/dashboard/inspector-expert/Form/ReviseForm.jsx @@ -0,0 +1,104 @@ +import {REVISE_INSPECTOR_EXPERT} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import useRequest from "@/lib/app/hooks/useRequest"; +import EditIcon from "@mui/icons-material/Edit"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Revise = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("ReviseDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + + requestServer(`${REVISE_INSPECTOR_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("ReviseDialog.revise")} + + + + + + + + + + + + + + ); +}; +export default Revise; \ No newline at end of file diff --git a/src/components/dashboard/inspector-expert/TableRowActions.jsx b/src/components/dashboard/inspector-expert/TableRowActions.jsx new file mode 100644 index 0000000..f76c2d2 --- /dev/null +++ b/src/components/dashboard/inspector-expert/TableRowActions.jsx @@ -0,0 +1,29 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" +import ReviseForm from "./Form/ReviseForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/inspector-expert/TableTollbar.jsx b/src/components/dashboard/inspector-expert/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/inspector-expert/index.jsx b/src/components/dashboard/inspector-expert/index.jsx new file mode 100644 index 0000000..5eeb329 --- /dev/null +++ b/src/components/dashboard/inspector-expert/index.jsx @@ -0,0 +1,201 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_INSPECTOR_EXPERT} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardInspectorExpertComponent() { + const t = useTranslations(); + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("InspectorExpert.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("InspectorExpert.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("InspectorExpert.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("InspectorExpert.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("InspectorExpert.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("InspectorExpert.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("InspectorExpert.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardInspectorExpertComponent; diff --git a/src/components/dashboard/loan-follow-up/index.jsx b/src/components/dashboard/loan-follow-up/index.jsx deleted file mode 100644 index e69147e..0000000 --- a/src/components/dashboard/loan-follow-up/index.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import CenterLayout from "@/layouts/CenterLayout"; -import DashboardLayouts from "@/layouts/dashboardLayouts"; -import useUser from "@/lib/app/hooks/useUser"; -import { useTranslations } from "next-intl"; -import React from "react"; - -const DashboardLoanFollowUpComponent = () => { - const t = useTranslations(); - const { token } = useUser(); - return ( - - -

چه کشکی چه پشمی

-
-
- ); -}; - -export default DashboardLoanFollowUpComponent; diff --git a/src/components/dashboard/loan-request/index.jsx b/src/components/dashboard/loan-request/index.jsx deleted file mode 100644 index b13cf78..0000000 --- a/src/components/dashboard/loan-request/index.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import CenterLayout from "@/layouts/CenterLayout"; -import DashboardLayouts from "@/layouts/dashboardLayouts"; -import useUser from "@/lib/app/hooks/useUser"; -import { useTranslations } from "next-intl"; -import React from "react"; - -const DashboardLoanRequestComponent = () => { - const t = useTranslations(); - const { token } = useUser(); - return ( - - -

نکنه وامم میخوای؟؟؟

-
-
- ); -}; - -export default DashboardLoanRequestComponent; diff --git a/src/components/dashboard/machinary-office/Form/ConfirmForm.jsx b/src/components/dashboard/machinary-office/Form/ConfirmForm.jsx new file mode 100644 index 0000000..ab4b11f --- /dev/null +++ b/src/components/dashboard/machinary-office/Form/ConfirmForm.jsx @@ -0,0 +1,178 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_MACHINARY_OFFICE} from "@/core/data/apiRoutes"; +import * as Yup from "yup"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + proposed_amount: Yup.number().positive(t("ConfirmDialog.proposed_amount_positive")).required(t("ConfirmDialog.proposed_amount_error")), + }) + const formik = useFormik({ + initialValues: { + description: "", + proposed_amount: "", + confirm_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("proposed_amount", values.proposed_amount); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_MACHINARY_OFFICE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleAmountChange = (event) => { + formik.setFieldValue("proposed_amount", event.target.value); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + + {t("ConfirmDialog.proposed_amount")}{t("ConfirmDialog.unit")}} + type="number" + inputProps={{ + min: 0, + pattern: "[0-9]*", + }} + variant="outlined" + value={formik.values.proposed_amount} + onChange={handleAmountChange} + onBlur={formik.handleBlur("proposed_amount")} + error={ + formik.touched.proposed_amount && + Boolean(formik.errors.proposed_amount) + } + helperText={ + formik.touched.proposed_amount && formik.errors.proposed_amount + } + sx={{mt: 1}} + fullWidth + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/machinary-office/Form/RejectForm.jsx b/src/components/dashboard/machinary-office/Form/RejectForm.jsx new file mode 100644 index 0000000..61cec90 --- /dev/null +++ b/src/components/dashboard/machinary-office/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_MACHINARY_OFFICE} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_MACHINARY_OFFICE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/machinary-office/TableRowActions.jsx b/src/components/dashboard/machinary-office/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/machinary-office/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/machinary-office/TableTolbar.jsx b/src/components/dashboard/machinary-office/TableTolbar.jsx new file mode 100644 index 0000000..e267691 --- /dev/null +++ b/src/components/dashboard/machinary-office/TableTolbar.jsx @@ -0,0 +1,13 @@ +import {Stack, Tooltip} from "@mui/material"; +import {useTranslations} from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/machinary-office/index.jsx b/src/components/dashboard/machinary-office/index.jsx new file mode 100644 index 0000000..8f68209 --- /dev/null +++ b/src/components/dashboard/machinary-office/index.jsx @@ -0,0 +1,232 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_MACHINARY_OFFICE} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardMachinaryOfficeComponent() { + const t = useTranslations(); + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("PassengerOffice.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("MachinaryOffice.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("MachinaryOffice.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("MachinaryOffice.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("MachinaryOffice.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("MachinaryOffice.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("MachinaryOffice.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("MachinaryOffice.vehicle_type"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("MachinaryOffice.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardMachinaryOfficeComponent; diff --git a/src/components/dashboard/navgan-province-manager/Form/ConfirmForm.jsx b/src/components/dashboard/navgan-province-manager/Form/ConfirmForm.jsx new file mode 100644 index 0000000..a4d0c1a --- /dev/null +++ b/src/components/dashboard/navgan-province-manager/Form/ConfirmForm.jsx @@ -0,0 +1,143 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_NAVGAN_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_NAVGAN_PROVINCE_MANAGER}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/navgan-province-manager/Form/RejectForm.jsx b/src/components/dashboard/navgan-province-manager/Form/RejectForm.jsx new file mode 100644 index 0000000..6f81b4a --- /dev/null +++ b/src/components/dashboard/navgan-province-manager/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_NAVGAN_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_NAVGAN_PROVINCE_MANAGER}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/navgan-province-manager/TableRowActions.jsx b/src/components/dashboard/navgan-province-manager/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/navgan-province-manager/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/navgan-province-manager/TableTollbar.jsx b/src/components/dashboard/navgan-province-manager/TableTollbar.jsx new file mode 100644 index 0000000..e267691 --- /dev/null +++ b/src/components/dashboard/navgan-province-manager/TableTollbar.jsx @@ -0,0 +1,13 @@ +import {Stack, Tooltip} from "@mui/material"; +import {useTranslations} from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/navgan-province-manager/index.jsx b/src/components/dashboard/navgan-province-manager/index.jsx new file mode 100644 index 0000000..702175c --- /dev/null +++ b/src/components/dashboard/navgan-province-manager/index.jsx @@ -0,0 +1,233 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_NAVGAN_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardNavganProvinceManagerComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("NavganProvinceManager.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("NavganProvinceManager.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("NavganProvinceManager.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("NavganProvinceManager.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("NavganProvinceManager.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("NavganProvinceManager.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("NavganProvinceManager.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("NavganProvinceManager.vehicle_type"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("NavganProvinceManager.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardNavganProvinceManagerComponent; diff --git a/src/components/dashboard/passenger-boss/Form/ConfirmForm.jsx b/src/components/dashboard/passenger-boss/Form/ConfirmForm.jsx new file mode 100644 index 0000000..d4305f5 --- /dev/null +++ b/src/components/dashboard/passenger-boss/Form/ConfirmForm.jsx @@ -0,0 +1,178 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import * as Yup from "yup"; +import useRequest from "@/lib/app/hooks/useRequest"; +import {CONFIRM_PASSENGER_BOSS} from "@/core/data/apiRoutes"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + approved_amount: Yup.number().positive(t("ConfirmDialog.approved_amount_positive")).required(t("ConfirmDialog.approved_amount_error")) + }); + const formik = useFormik({ + initialValues: { + description: "", + approved_amount: "", + confirm_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("approved_amount", values.approved_amount); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_PASSENGER_BOSS}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleAmountChange = (event) => { + formik.setFieldValue("approved_amount", event.target.value); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + + {t("ConfirmDialog.approved_amount")}{t("ConfirmDialog.unit")}} + type="number" + inputProps={{ + min: 0, + pattern: "[0-9]*", + }} + variant="outlined" + value={formik.values.approved_amount} + onChange={handleAmountChange} + onBlur={formik.handleBlur("approved_amount")} + error={ + formik.touched.approved_amount && + Boolean(formik.errors.approved_amount) + } + helperText={ + formik.touched.approved_amount && formik.errors.approved_amount + } + sx={{mt: 1}} + fullWidth + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/passenger-boss/Form/RejectForm.jsx b/src/components/dashboard/passenger-boss/Form/RejectForm.jsx new file mode 100644 index 0000000..3688ae7 --- /dev/null +++ b/src/components/dashboard/passenger-boss/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_PASSENGER_BOSS} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_PASSENGER_BOSS}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/passenger-boss/TableRowActions.jsx b/src/components/dashboard/passenger-boss/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/passenger-boss/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/passenger-boss/TableTollbar.jsx b/src/components/dashboard/passenger-boss/TableTollbar.jsx new file mode 100644 index 0000000..e267691 --- /dev/null +++ b/src/components/dashboard/passenger-boss/TableTollbar.jsx @@ -0,0 +1,13 @@ +import {Stack, Tooltip} from "@mui/material"; +import {useTranslations} from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/passenger-boss/index.jsx b/src/components/dashboard/passenger-boss/index.jsx new file mode 100644 index 0000000..5fe7342 --- /dev/null +++ b/src/components/dashboard/passenger-boss/index.jsx @@ -0,0 +1,234 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_PASSENGER_BOSS} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; + +function DashboardPassengerOfficeComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("PassengerBoss.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("PassengerBoss.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("PassengerBoss.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("PassengerBoss.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("PassengerBoss.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("PassengerBoss.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("PassengerBoss.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("PassengerBoss.vehicle_type"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("PassengerBoss.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + } + enableLastUpdate={true} + enablePinning={true} + enableDensityToggle={false} + initialState={{density: 'compact'}} //compact (small) //comfortable (medium) //spacious (large) + enableColumnFilters={true} + enableHiding={true} + enableFullScreenToggle={false} + enableGlobalFilter={false} + enableColumnResizing={false} // if you want true this you shold change renderRowActions props ** see https://www.material-react-table.com/docs/guides/row-actions + enableRowActions={true} + TableRowAction={TableRowActions} + /> + + + ); +} + +export default DashboardPassengerOfficeComponent; diff --git a/src/components/dashboard/passenger-office/Form/ConfirmForm.jsx b/src/components/dashboard/passenger-office/Form/ConfirmForm.jsx new file mode 100644 index 0000000..1be22c8 --- /dev/null +++ b/src/components/dashboard/passenger-office/Form/ConfirmForm.jsx @@ -0,0 +1,142 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useRequest from "@/lib/app/hooks/useRequest"; +import {CONFIRM_PASSENGER_OFFICE} from "@/core/data/apiRoutes"; +import useNotification from "@/lib/app/hooks/useNotification"; + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_PASSENGER_OFFICE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/passenger-office/Form/RejectForm.jsx b/src/components/dashboard/passenger-office/Form/RejectForm.jsx new file mode 100644 index 0000000..b187a2b --- /dev/null +++ b/src/components/dashboard/passenger-office/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_PASSENGER_OFFICE} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_PASSENGER_OFFICE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/passenger-office/TableRowActions.jsx b/src/components/dashboard/passenger-office/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/passenger-office/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/passenger-office/TableTollbar.jsx b/src/components/dashboard/passenger-office/TableTollbar.jsx new file mode 100644 index 0000000..e267691 --- /dev/null +++ b/src/components/dashboard/passenger-office/TableTollbar.jsx @@ -0,0 +1,13 @@ +import {Stack, Tooltip} from "@mui/material"; +import {useTranslations} from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/passenger-office/index.jsx b/src/components/dashboard/passenger-office/index.jsx new file mode 100644 index 0000000..d36acff --- /dev/null +++ b/src/components/dashboard/passenger-office/index.jsx @@ -0,0 +1,235 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {faIR} from "@mui/x-date-pickers/locales"; +import {GET_PASSENGER_OFFICE} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} from "@mui/x-date-pickers"; +import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "jalali-moment"; +import DataTable from "@/core/components/DataTable"; + +function DashboardPassengerOfficeComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("PassengerOffice.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("PassengerOffice.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("PassengerOffice.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("PassengerOffice.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("PassengerOffice.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + actionbar: {actions: ["accept", "today"]}, + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | YYYY/MM/DD"), + id: "updated_at", + header: t("PassengerOffice.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("PassengerOffice.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("PassengerOffice.vehicle_type"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("PassengerOffice.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + } + enableLastUpdate={true} + enablePinning={true} + enableDensityToggle={false} + initialState={{density: 'compact'}} //compact (small) //comfortable (medium) //spacious (large) + enableColumnFilters={true} + enableHiding={true} + enableFullScreenToggle={false} + enableGlobalFilter={false} + enableColumnResizing={false} // if you want true this you shold change renderRowActions props ** see https://www.material-react-table.com/docs/guides/row-actions + enableRowActions={true} + TableRowAction={TableRowActions} + /> + + + ); +} + +export default DashboardPassengerOfficeComponent; diff --git a/src/components/dashboard/province-head-expert/Form/ConfirmForm.jsx b/src/components/dashboard/province-head-expert/Form/ConfirmForm.jsx new file mode 100644 index 0000000..c4cc607 --- /dev/null +++ b/src/components/dashboard/province-head-expert/Form/ConfirmForm.jsx @@ -0,0 +1,141 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_PROVINCE_HEAD_EXPERT} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_PROVINCE_HEAD_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/province-head-expert/Form/RejectForm.jsx b/src/components/dashboard/province-head-expert/Form/RejectForm.jsx new file mode 100644 index 0000000..e41f95a --- /dev/null +++ b/src/components/dashboard/province-head-expert/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_PROVINCE_HEAD_EXPERT} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_PROVINCE_HEAD_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/province-head-expert/Form/ReviceForm.jsx b/src/components/dashboard/province-head-expert/Form/ReviceForm.jsx new file mode 100644 index 0000000..0c61316 --- /dev/null +++ b/src/components/dashboard/province-head-expert/Form/ReviceForm.jsx @@ -0,0 +1,108 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, +} from "@mui/material"; +import EditIcon from '@mui/icons-material/Edit'; +import {useFormik} from "formik"; +import {REVISE_PROVINCE_HEAD_EXPERT} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import * as Yup from "yup"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Revise = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + + requestServer(`${REVISE_PROVINCE_HEAD_EXPERT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ReviseDialog.revise")} + + + + + + + + + + + + + + ); +}; +export default Revise; \ No newline at end of file diff --git a/src/components/dashboard/province-head-expert/TableRowActions.jsx b/src/components/dashboard/province-head-expert/TableRowActions.jsx new file mode 100644 index 0000000..b92f311 --- /dev/null +++ b/src/components/dashboard/province-head-expert/TableRowActions.jsx @@ -0,0 +1,29 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" +import ReviseForm from "@/components/dashboard/province-head-expert/Form/ReviceForm"; + +const TableRowActions = ({row, mutate, fetchUrl}) => { + + return ( + + + + + + ); +}; + +export default TableRowActions; diff --git a/src/components/dashboard/province-head-expert/TableTollbar.jsx b/src/components/dashboard/province-head-expert/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/province-head-expert/index.jsx b/src/components/dashboard/province-head-expert/index.jsx new file mode 100644 index 0000000..ded6eef --- /dev/null +++ b/src/components/dashboard/province-head-expert/index.jsx @@ -0,0 +1,202 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_PROVINCE_HEAD_EXPERT} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import {LocalizationProvider, MobileDateTimePicker,} 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 DataTable from "@/core/components/DataTable"; +import TableRowActions from "./TableRowActions" + +function DashboardProvinceHeadExpertComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("ProvinceHeadExpert.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("ProvinceHeadExpert.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("ProvinceHeadExpert.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("ProvinceHeadExpert.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("ProvinceHeadExpert.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("ProvinceHeadExpert.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("ProvinceHeadExpert.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardProvinceHeadExpertComponent; diff --git a/src/components/dashboard/refahi-province-manager/Form/ConfirmForm.jsx b/src/components/dashboard/refahi-province-manager/Form/ConfirmForm.jsx new file mode 100644 index 0000000..f14421c --- /dev/null +++ b/src/components/dashboard/refahi-province-manager/Form/ConfirmForm.jsx @@ -0,0 +1,143 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useRequest from "@/lib/app/hooks/useRequest"; +import {CONFIRM_REFAHI_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_REFAHI_PROVINCE_MANAGER}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/refahi-province-manager/Form/RejectForm.jsx b/src/components/dashboard/refahi-province-manager/Form/RejectForm.jsx new file mode 100644 index 0000000..f253844 --- /dev/null +++ b/src/components/dashboard/refahi-province-manager/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_REFAHI_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_REFAHI_PROVINCE_MANAGER}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/refahi-province-manager/TableRowActions.jsx b/src/components/dashboard/refahi-province-manager/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/refahi-province-manager/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/refahi-province-manager/TableTollbar.jsx b/src/components/dashboard/refahi-province-manager/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/refahi-province-manager/index.jsx b/src/components/dashboard/refahi-province-manager/index.jsx new file mode 100644 index 0000000..8122fcf --- /dev/null +++ b/src/components/dashboard/refahi-province-manager/index.jsx @@ -0,0 +1,204 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {faIR} from "@mui/x-date-pickers/locales"; +import {GET_REFAHI_PROVINCE_MANAGER} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} from "@mui/x-date-pickers"; +import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "jalali-moment"; +import DataTable from "@/core/components/DataTable"; + +function DashboardRefahiProvinceManagerComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("RefahiProvinceManager.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("RefahiProvinceManager.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("RefahiProvinceManager.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("RefahiProvinceManager.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("RefahiProvinceManager.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + actionbar: {actions: ["accept", "today"]}, + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | YYYY/MM/DD"), + id: "updated_at", + header: t("RefahiProvinceManager.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("RefahiProvinceManager.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + } + enableLastUpdate={true} + enablePinning={true} + enableDensityToggle={false} + initialState={{density: 'compact'}} //compact (small) //comfortable (medium) //spacious (large) + enableColumnFilters={true} + enableHiding={true} + enableFullScreenToggle={false} + enableGlobalFilter={false} + enableColumnResizing={false} // if you want true this you should change renderRowActions props ** see https://www.material-react-table.com/docs/guides/row-actions + enableRowActions={true} + TableRowAction={TableRowActions} + /> + + + ); +} + +export default DashboardRefahiProvinceManagerComponent; diff --git a/src/components/dashboard/transportation-assistance/Form/ConfirmForm.jsx b/src/components/dashboard/transportation-assistance/Form/ConfirmForm.jsx new file mode 100644 index 0000000..7aba85c --- /dev/null +++ b/src/components/dashboard/transportation-assistance/Form/ConfirmForm.jsx @@ -0,0 +1,143 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import useDirection from "@/lib/app/hooks/useDirection"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_TRANSPORTATION_ASSISTANCE} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const {directionApp} = useDirection(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_TRANSPORTATION_ASSISTANCE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/transportation-assistance/Form/RejectForm.jsx b/src/components/dashboard/transportation-assistance/Form/RejectForm.jsx new file mode 100644 index 0000000..d7a41df --- /dev/null +++ b/src/components/dashboard/transportation-assistance/Form/RejectForm.jsx @@ -0,0 +1,148 @@ +import {REJECT_TRANSPORTATION_ASSISTANCE} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import useDirection from "@/lib/app/hooks/useDirection"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; +import useNotification from "@/lib/app/hooks/useNotification"; + + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const {directionApp} = useDirection(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + const {update_notification} = useNotification() + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_TRANSPORTATION_ASSISTANCE}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + update_notification() + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/transportation-assistance/TableRowActions.jsx b/src/components/dashboard/transportation-assistance/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/transportation-assistance/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/transportation-assistance/TableTollbar.jsx b/src/components/dashboard/transportation-assistance/TableTollbar.jsx new file mode 100644 index 0000000..e267691 --- /dev/null +++ b/src/components/dashboard/transportation-assistance/TableTollbar.jsx @@ -0,0 +1,13 @@ +import {Stack, Tooltip} from "@mui/material"; +import {useTranslations} from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/transportation-assistance/index.jsx b/src/components/dashboard/transportation-assistance/index.jsx new file mode 100644 index 0000000..8f96ed4 --- /dev/null +++ b/src/components/dashboard/transportation-assistance/index.jsx @@ -0,0 +1,233 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_TRANSPORTATION_ASSISTANCE} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} from "@mui/x-date-pickers"; +import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import {faIR} from "@mui/x-date-pickers/locales"; +import moment from "jalali-moment"; +import DataTable from "@/core/components/DataTable"; + +function DashboardTransportationAssistanceComponent() { + const t = useTranslations(); + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("TransportationAssistance.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("TransportationAssistance.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("TransportationAssistance.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("TransportationAssistance.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("TransportationAssistance.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("TransportationAssistance.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("TransportationAssistance.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("TransportationAssistance.vehicle_type"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("TransportationAssistance.state_name"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardTransportationAssistanceComponent; diff --git a/src/components/errors/403.jsx b/src/components/errors/403.jsx new file mode 100644 index 0000000..ce91443 --- /dev/null +++ b/src/components/errors/403.jsx @@ -0,0 +1,37 @@ +import CenterLayout from "@/layouts/CenterLayout"; +import FullPageLayout from "@/layouts/FullPageLayout"; +import {Button, Typography} from "@mui/material"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; +import {useTranslations} from "next-intl"; +import TitlePage from "@/core/components/TitlePage"; +import Svg403 from "@/core/components/svgs/Svg403"; + +const UnAuthorizedComponent = () => { + const t = useTranslations(); + + return ( + <> + + + + + + {t("ErrorPage.custom_403")} + + + + + + ); +}; + +export default UnAuthorizedComponent; diff --git a/src/components/errors/404.jsx b/src/components/errors/404.jsx new file mode 100644 index 0000000..acfd418 --- /dev/null +++ b/src/components/errors/404.jsx @@ -0,0 +1,37 @@ +import CenterLayout from "@/layouts/CenterLayout"; +import FullPageLayout from "@/layouts/FullPageLayout"; +import {Button, Typography} from "@mui/material"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; +import {useTranslations} from "next-intl"; +import TitlePage from "@/core/components/TitlePage"; +import Svg404 from "@/core/components/svgs/Svg404"; + +const NotFoundComponent = () => { + const t = useTranslations(); + + return ( + <> + + + + + + {t("ErrorPage.custom_404")} + + + + + + ); +}; + +export default NotFoundComponent; diff --git a/src/components/errors/500.jsx b/src/components/errors/500.jsx new file mode 100644 index 0000000..10e9d12 --- /dev/null +++ b/src/components/errors/500.jsx @@ -0,0 +1,48 @@ +import CenterLayout from "@/layouts/CenterLayout"; +import FullPageLayout from "@/layouts/FullPageLayout"; +import {Box, Button, Container, Stack, Typography} from "@mui/material"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; +import {useTranslations} from "next-intl"; +import Image from "next/image"; +import TitlePage from "@/core/components/TitlePage"; + +const ServerErrorComponent = () => { + const t = useTranslations(); + + return ( + <> + + + + + + + {t("app_name")} + + + {t("ErrorPage.custom_500")} + + + + + + + + ); +}; + +export default ServerErrorComponent; diff --git a/src/components/first/index.jsx b/src/components/first/index.jsx index adf4393..cd5b5a5 100644 --- a/src/components/first/index.jsx +++ b/src/components/first/index.jsx @@ -1,53 +1,56 @@ -import dahsboardImage from "&/images/dashboard.svg"; -import { NextLinkComposed } from "@/core/components/LinkRouting"; -import StyledImage from "@/core/components/StyledImage"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; import CenterLayout from "@/layouts/CenterLayout"; import FullPageLayout from "@/layouts/FullPageLayout"; import useUser from "@/lib/app/hooks/useUser"; -import { Button, Typography } from "@mui/material"; -import { useTranslations } from "next-intl"; +import {Button, Stack, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; +import SvgDashboard from "@/core/components/svgs/SvgDashboard"; +import process from "next/dist/build/webpack/loaders/resolve-url-loader/lib/postcss"; const FirstComponent = () => { - const t = useTranslations(); - const { isAuth } = useUser(); + const t = useTranslations(); + const {isAuth} = useUser(); - return ( - - - - - {t("app_name")} - - {isAuth ? ( - - ) : ( - - )} - - - ); + return ( + + + + + {t("app_name")} + + {isAuth ? ( + + ) : ( + + )} + + + v{process.env.NEXT_PUBLIC_API_VERSION} + + + ); }; export default FirstComponent; diff --git a/src/components/login-expert/index.jsx b/src/components/login-expert/index.jsx index 92d4e36..2eaa3bd 100644 --- a/src/components/login-expert/index.jsx +++ b/src/components/login-expert/index.jsx @@ -1,170 +1,153 @@ import LinkRouting from "@/core/components/LinkRouting"; -// import Notifications from "@/core/components/notifications"; import PasswordField from "@/core/components/PasswordField"; import StyledForm from "@/core/components/StyledForm"; -// import { GET_USER_TOKEN } from "@/core/data/apiRoutes"; +import {GET_USER_TOKEN} from "@/core/data/apiRoutes"; import CenterLayout from "@/layouts/CenterLayout"; import FullPageLayout from "@/layouts/FullPageLayout"; -import useDirection from "@/lib/app/hooks/useDirection"; import useUser from "@/lib/app/hooks/useUser"; import LoginIcon from "@mui/icons-material/Login"; -import PersonAddIcon from "@mui/icons-material/PersonAdd"; -import { - Box, - Button, - Container, - Paper, - Stack, - TextField, - Typography, -} from "@mui/material"; -// import axios from "axios"; -import { Field, Formik } from "formik"; -import { useTranslations } from "next-intl"; -import Image from "next/image"; -import { useSearchParams } from "next/navigation"; +import {Box, Button, Container, Paper, Stack, TextField, Typography,} from "@mui/material"; +import {Field, Formik} from "formik"; +import {useTranslations} from "next-intl"; +import {useSearchParams} from "next/navigation"; import * as Yup from "yup"; +import useDirection from "@/lib/app/hooks/useDirection"; +import SvgLogin from "@/core/components/svgs/SvgLogin"; +import useRequest from "@/lib/app/hooks/useRequest"; const LoginComponent = () => { - const t = useTranslations(); - const { directionApp } = useDirection(); - const { setToken } = useUser(); // pass token to set token + const t = useTranslations(); + const {directionApp} = useDirection(); // should delete because we don't have direction anymore + const {setToken} = useUser(); // pass token to set token + const requestServer = useRequest() - // gettin url query - const searchParams = useSearchParams(); - const backUrlDecodedPath = searchParams.get("back_url"); + // getting url query + const searchParams = useSearchParams(); + const backUrlDecodedPath = searchParams.get("back_url"); - // formik properties -// const handleSubmit = async (values, props) => { -// await axios -// .post(GET_USER_TOKEN, { -// username: values.username, -// password: values.password, -// }) -// .then(function (response) { -// setToken(response.data.token); -// }) -// .catch(function (error) { -// Notifications(directionApp, error.response, t); -// props.setSubmitting(false); -// }); -// }; - const initialValues = { - username: "", - password: "", - }; - const validationSchema = Yup.object().shape({ - username: Yup.string().required(t("LoginPage.error_message_required")), - password: Yup.string().required(t("LoginPage.error_message_required")), - }); + //formik properties + const handleSubmit = (values, props) => { + requestServer(GET_USER_TOKEN, 'post', { + data: { + username: values.username, + password: values.password, + }, + success: { + notification: {show: false} + } + }).then((response) => { + setToken(response.data.token) + }).catch(() => { + props.setSubmitting(false) + }) + }; + const initialValues = { + username: "", + password: "", + }; + const validationSchema = Yup.object().shape({ + username: Yup.string().required(t("LoginPage.error_message_required")), + password: Yup.string().required(t("LoginPage.error_message_required")), + }); - return ( - - - - - - {(props) => ( - - - {t("app_name")} - - - {t("login_expert")} - - - - - - - - - - - - - - - )} - - - - - - - {t("LoginPage.link_routing_back_to")}{" "} - {backUrlDecodedPath - ? t("LoginPage.link_routing_previuos_page") - : t("LoginPage.link_routing_main_page")} - - - - ); + {(props) => ( + + + + + + {t("login_expert")} + + + + + + + + + + + + )} + + + + + + + {t("LoginPage.link_routing_back_to")}{" "} + {backUrlDecodedPath + ? t("LoginPage.link_routing_previuos_page") + : t("LoginPage.link_routing_main_page")} + + + + ); }; export default LoginComponent; diff --git a/src/core/components/AvatarUpload.jsx b/src/core/components/AvatarUpload.jsx new file mode 100644 index 0000000..03a9cba --- /dev/null +++ b/src/core/components/AvatarUpload.jsx @@ -0,0 +1,128 @@ +import {Avatar, Box, TextField} from "@mui/material"; +import {useState} from "react"; +import DeleteIcon from "@mui/icons-material/Delete"; +import AddIcon from "@mui/icons-material/Add"; + +const AvatarUpload = ({user, setFieldValue, valueAvatar, changeFlag}) => { + const [selectedImage, setSelectedImage] = useState(user.expert_avatar); + const [isHovered, setIsHovered] = useState(false); + + const handleImageChange = (event) => { + const newImage = event.target?.files?.[0]; + if (newImage) { + setSelectedImage(URL.createObjectURL(newImage)); + setFieldValue(valueAvatar, newImage); + setFieldValue(changeFlag, true); + } else { + setSelectedImage(""); + setFieldValue(valueAvatar, null); + } + }; + + const handleDeleteImage = () => { + setSelectedImage(""); + setFieldValue(valueAvatar, null); + setFieldValue(changeFlag, true); + }; + + const handleMouseEnter = () => { + setIsHovered(true); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + return ( + + + + + {isHovered && ( + + {selectedImage ? ( + + ) : ( + + )} + + )} + + + + + ); +}; + +export default AvatarUpload; diff --git a/src/core/components/DataTable.jsx b/src/core/components/DataTable.jsx new file mode 100644 index 0000000..b3b0f26 --- /dev/null +++ b/src/core/components/DataTable.jsx @@ -0,0 +1,176 @@ +import {useTranslations} from "next-intl"; +import useLanguage from "@/lib/app/hooks/useLanguage"; +import {useEffect, useMemo, useState} from "react"; +import moment from "moment-jalaali"; +import useSWR from "swr"; +import {Typography} from "@mui/material"; +import MaterialReactTable from "material-react-table"; +import useRequest from "@/lib/app/hooks/useRequest"; + +function DataTable(props) { + const requestServer = useRequest({auth: true}) + const fetcher = (...args) => { + return requestServer(args, 'get', { + pending: false, + success: {notification: {show: false}} + }).then((response) => { + setRowCount(response.data.meta.totalRowCount); + return response.data.data; + }).catch(() => { + }) + }; + const t = useTranslations(); + const {languageApp, languageList} = useLanguage(); + const [columnFilters, setColumnFilters] = useState([]); + const [sorting, setSorting] = useState([]); + const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10}); + const [rowCount, setRowCount] = useState(0); + const [columnFilterFns, setColumnFilterFns] = useState(() => { + let output = {}; + const list = props.columns.map((item) => + item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""} + ); + for (var key in list) { + var nestedObj = list[key]; + for (var nestedKey in nestedObj) { + output[nestedKey] = nestedObj[nestedKey]; + } + } + return output; + }); + + const [updateTime, setupdateTime] = useState( + moment().format("HH:mm | jYYYY/jM/jD") + ); + + const tableLocalization = useMemo( + () => + languageList.find((item) => item.key == languageApp).tableLocalization, + [languageApp, languageList] + ); + + const fetchUrl = useMemo(() => { + const url = new URL(props.tableUrl); + url.searchParams.set( + "start", + `${pagination.pageIndex * pagination.pageSize}` + ); + const filters = columnFilters.map((filter) => { + let datatype; + for (const i in props.columns) { + if (props.columns[i].id == filter.id) { + datatype = props.columns[i].datatype; + } + } + return { + ...filter, + fn: columnFilterFns[filter.id], + datatype: datatype, + }; + }); + url.searchParams.set("size", pagination.pageSize); + url.searchParams.set("filters", JSON.stringify(filters ?? [])); + url.searchParams.set("sorting", JSON.stringify(sorting ?? [])); + return url; + }, [ + props.tableUrl, + columnFilters, + columnFilterFns, + pagination, + sorting, + props.columns, + ]); + + const {data, isValidating, mutate} = useSWR(fetchUrl, fetcher, { + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false + }); + + useEffect(() => { + setupdateTime(moment().format("HH:mm | jYYYY/jM/jD")); + }, [isValidating, languageApp]); + + return ( + ( + <> + {props.enableCustomToolbar /* send condition */ + ? props.CustomToolbar /* send component */ + : ""} + + )} + renderBottomToolbarCustomActions={({table}) => ( + <> + {props.enableLastUpdate /* send condition */ ? ( + + {t("last_updated_at")}: {updateTime} + + ) : ( + "" + )} + + )} + state={{ + isLoading: isValidating, + columnFilters, + columnFilterFns, + pagination, + sorting, + }} + positionActionsColumn={"last"} + enableRowActions={props.enableRowActions} + renderRowActions={({row}) => } + {...props} + /> + ); +} + +export default DataTable; \ No newline at end of file diff --git a/src/core/components/GlobalHead.jsx b/src/core/components/GlobalHead.jsx new file mode 100644 index 0000000..5d6186d --- /dev/null +++ b/src/core/components/GlobalHead.jsx @@ -0,0 +1,58 @@ +import Head from "next/head"; + +const GlobalHead = () => { + return ( + + + + + + + + + + + + + + + + + + + + + ) +} + +export default GlobalHead \ No newline at end of file diff --git a/src/core/components/ImageConvertor.jsx b/src/core/components/ImageConvertor.jsx new file mode 100644 index 0000000..9f99bc1 --- /dev/null +++ b/src/core/components/ImageConvertor.jsx @@ -0,0 +1,22 @@ +import ImageResize from "image-resize"; + +const ImageResizer = async (image) => { + const imageResize = new ImageResize({ + quality: 1, + format: "jpg", + outputType: "base64", + width: 400, + }); + + const get = await imageResize.get(image); + const resize = await imageResize.resize(get).then(); + const output = await imageResize.output(resize).then(); + + const avatar = await (await import("image-to-file-converter")) + .base64ToFile(output) + .then(); + + return avatar; +}; + +export default ImageResizer; diff --git a/src/core/components/LinkRouting.jsx b/src/core/components/LinkRouting.jsx index ff33c86..f8fac0a 100644 --- a/src/core/components/LinkRouting.jsx +++ b/src/core/components/LinkRouting.jsx @@ -1,116 +1,116 @@ import MuiLink from "@mui/material/Link"; -import { styled } from "@mui/material/styles"; +import {styled} from "@mui/material/styles"; import clsx from "clsx"; import NextLink from "next/link"; -import { useRouter } from "next/router"; +import {useRouter} from "next/router"; import * as React from "react"; // Add support for the sx prop for consistency with the other branches. const Anchor = styled("a")({}); export const NextLinkComposed = React.forwardRef(function NextLinkComposed( - props, - ref + props, + ref ) { - const { - to, - linkAs, - replace, - scroll, - shallow, - prefetch, - legacyBehavior = true, - locale, - ...other - } = props; + const { + to, + linkAs, + replace, + scroll, + shallow, + prefetch, + legacyBehavior = true, + locale, + ...other + } = props; - return ( - - - - ); + return ( + + + + ); }); // A styled version of the Next.js Link component: // https://nextjs.org/docs/api-reference/next/link const LinkRouting = React.forwardRef(function Link(props, ref) { - const { - activeClassName = "active", - as, - className: classNameProps, - href, - legacyBehavior, - linkAs: linkAsProp, - locale, - noLinkStyle, - prefetch, - replace, - role, // Link don't have roles. - scroll, - shallow, - ...other - } = props; + const { + activeClassName = "active", + as, + className: classNameProps, + href, + legacyBehavior, + linkAs: linkAsProp, + locale, + noLinkStyle, + prefetch, + replace, + role, // Link don't have roles. + scroll, + shallow, + ...other + } = props; - const router = useRouter(); - const pathname = typeof href === "string" ? href : href.pathname; - const className = clsx(classNameProps, { - [activeClassName]: router.pathname === pathname && activeClassName, - }); + const router = useRouter(); + const pathname = typeof href === "string" ? href : href.pathname; + const className = clsx(classNameProps, { + [activeClassName]: router.pathname === pathname && activeClassName, + }); - const isExternal = - typeof href === "string" && - (href.indexOf("http") === 0 || href.indexOf("mailto:") === 0); + const isExternal = + typeof href === "string" && + (href.indexOf("http") === 0 || href.indexOf("mailto:") === 0); - if (isExternal) { - if (noLinkStyle) { - return ; + if (isExternal) { + if (noLinkStyle) { + return ; + } + + return ; } - return ; - } + const linkAs = linkAsProp || as; + const nextjsProps = { + to: href, + linkAs, + replace, + scroll, + shallow, + prefetch, + legacyBehavior, + locale, + }; - const linkAs = linkAsProp || as; - const nextjsProps = { - to: href, - linkAs, - replace, - scroll, - shallow, - prefetch, - legacyBehavior, - locale, - }; + if (noLinkStyle) { + return ( + + ); + } - if (noLinkStyle) { return ( - + ); - } - - return ( - - ); }); export default LinkRouting; diff --git a/src/core/components/LoadingHardPage.jsx b/src/core/components/LoadingHardPage.jsx index 5da632d..c3b24d6 100644 --- a/src/core/components/LoadingHardPage.jsx +++ b/src/core/components/LoadingHardPage.jsx @@ -1,44 +1,42 @@ -import { Backdrop, Fade, styled } from "@mui/material"; -import StyledImage from "./StyledImage"; +import {Backdrop, Box, styled} from "@mui/material"; +import SvgLoading from "@/core/components/svgs/SvgLoading"; -const LoadingImage = styled(StyledImage)({ - "@keyframes load": { - "0%": { - // opacity: 0, - transform: "scale(1)", +const LoadingImage = styled(Box)({ + "@keyframes load": { + "0%": { + // opacity: 0, + transform: "scale(1)", + }, + "50%": { + // opacity: 1, + transform: "scale(2)", + }, + "100%": { + // opacity: 0, + transform: "scale(1)", + }, }, - "50%": { - // opacity: 1, - transform: "scale(2)", - }, - "100%": { - // opacity: 0, - transform: "scale(1)", - }, - }, - animation: "load 2s infinite", + animation: "load 2s infinite", }); -const LoadingHardPage = ({ children, loading }) => { - return ( - <> - theme.zIndex.drawer + 1 }} - open={loading} - > - - - - - {children} - - ); +const LoadingHardPage = ({children, loading}) => { + return ( + <> + theme.zIndex.drawer + 1}} + open={loading} + > + + + + + {children} + + ); }; export default LoadingHardPage; diff --git a/src/core/components/Messages.jsx b/src/core/components/Messages.jsx index ea9cd29..8a5cfc9 100644 --- a/src/core/components/Messages.jsx +++ b/src/core/components/Messages.jsx @@ -1,22 +1,18 @@ import CenterLayout from "@/layouts/CenterLayout"; import FullPageLayout from "@/layouts/FullPageLayout"; -import StyledImage from "./StyledImage"; +import SvgLoading from "@/core/components/svgs/SvgLoading"; -const Message = ({ text, actions }) => { - return ( - - - - {text} - {actions} - - - ); +const Message = ({text, actions}) => { + return ( + + + + {text} + {actions} + + + ); }; export default Message; diff --git a/src/core/components/MuiDatePicker.jsx b/src/core/components/MuiDatePicker.jsx new file mode 100644 index 0000000..de6c5d5 --- /dev/null +++ b/src/core/components/MuiDatePicker.jsx @@ -0,0 +1,35 @@ +import {DatePicker, LocalizationProvider} from "@mui/x-date-pickers"; +import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "jalali-moment"; +import {useTranslations} from "next-intl"; + +export default function MuiDatePicker({ + setFieldValue, + selectType, + error, + helperText, + }) { + const t = useTranslations(); + + const handleDateChange = (date) => { + const selectedDate = moment(date).locale("fa"); // should add .format() at the end to format the data + setFieldValue(selectType, selectedDate); + }; + + return ( + + + + ); +} diff --git a/src/core/components/NetworkComponent.jsx b/src/core/components/NetworkComponent.jsx new file mode 100644 index 0000000..8ebbb68 --- /dev/null +++ b/src/core/components/NetworkComponent.jsx @@ -0,0 +1,34 @@ +import useNetwork from "@/lib/app/hooks/useNetwork"; +import {useEffect, useRef} from "react"; +import {toast} from "react-toastify"; +import WifiIcon from '@mui/icons-material/Wifi'; +import WifiOffIcon from '@mui/icons-material/WifiOff'; +import {useTranslations} from "next-intl"; + +const NetworkComponent = () => { + const toastId = useRef(null); + const network = useNetwork() + const t = useTranslations() + + useEffect(() => { + if (network.online) { + toast.update(toastId.current, { + type: toast.TYPE.SUCCESS, + render: t('online_message'), + autoClose: 2000, + closeButton: true, + closeOnClick: true, + icon: + }); + return + } + toast.dismiss() + toastId.current = toast.warn(t('offline_message'), { + autoClose: false, closeButton: false, closeOnClick: false, icon: + }) + }, [network.online]); + + return '' +} + +export default NetworkComponent \ No newline at end of file diff --git a/src/core/components/NoSsrHandler.jsx b/src/core/components/NoSsrHandler.jsx new file mode 100644 index 0000000..5a4c4e1 --- /dev/null +++ b/src/core/components/NoSsrHandler.jsx @@ -0,0 +1,8 @@ +import {NoSsr} from "@mui/material"; + +const NoSsrHandler = ({isBot, children}) => { + if (isBot) return children; + return {children}; +}; + +export default NoSsrHandler; diff --git a/src/core/components/PasswordField.jsx b/src/core/components/PasswordField.jsx index 5747bdb..d109b73 100644 --- a/src/core/components/PasswordField.jsx +++ b/src/core/components/PasswordField.jsx @@ -1,33 +1,33 @@ -import { useState } from "react"; -import { IconButton, InputAdornment, TextField } from "@mui/material"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; -import { Field } from "formik"; +import {useState} from "react"; +import {IconButton, InputAdornment, TextField} from "@mui/material"; +import {Visibility, VisibilityOff} from "@mui/icons-material"; +import {Field} from "formik"; const PasswordField = (props) => { - const [showPassword, setShowPassword] = useState(false); + const [showPassword, setShowPassword] = useState(false); - const handleClickShowPassword = () => { - setShowPassword(!showPassword); - }; + const handleClickShowPassword = () => { + setShowPassword(!showPassword); + }; - return ( - - - {showPassword ? : } - - - ), - }} - /> - ); + return ( + + + {showPassword ? : } + + + ), + }} + /> + ); }; export default PasswordField; diff --git a/src/core/components/StyledForm.jsx b/src/core/components/StyledForm.jsx index 1f299bb..41eeabc 100644 --- a/src/core/components/StyledForm.jsx +++ b/src/core/components/StyledForm.jsx @@ -1,5 +1,5 @@ -import { styled } from "@mui/material"; -import { Form } from "formik"; +import {styled} from "@mui/material"; +import {Form} from "formik"; const StyledForm = styled(Form)``; diff --git a/src/core/components/StyledImage.jsx b/src/core/components/StyledImage.jsx index 64391ad..58dd65f 100644 --- a/src/core/components/StyledImage.jsx +++ b/src/core/components/StyledImage.jsx @@ -1,4 +1,4 @@ -import { styled } from "@mui/material"; +import {styled} from "@mui/material"; import Image from "next/image"; const StyledImage = styled(Image)``; diff --git a/src/core/components/TitlePage.jsx b/src/core/components/TitlePage.jsx index 7bdcfc2..77c72ee 100644 --- a/src/core/components/TitlePage.jsx +++ b/src/core/components/TitlePage.jsx @@ -1,15 +1,15 @@ -import { useTranslations } from "next-intl"; +import {useTranslations} from "next-intl"; import Head from "next/head"; -const TitlePage = ({ text }) => { - const t = useTranslations(); - return ( - - - {text ? `${t("app_short_name")} | ${t(text)}` : t("app_short_name")} - - - ); +const TitlePage = ({text}) => { + const t = useTranslations(); + return ( + + + {text ? `${t("app_short_name")} | ${t(text)}` : t("app_short_name")} + + + ); }; export default TitlePage; diff --git a/src/core/components/UploadSystem.jsx b/src/core/components/UploadSystem.jsx new file mode 100644 index 0000000..b40fb46 --- /dev/null +++ b/src/core/components/UploadSystem.jsx @@ -0,0 +1,175 @@ +import {Box, Button, Paper, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; +import AddIcon from "@mui/icons-material/Add"; +import DeleteForeverIcon from "@mui/icons-material/DeleteForever"; +import {useRef} from "react"; + +const UploadSystem = ({ + selectedImage, + setselectedImage, + handleUploadChange, + fieldname, + setFieldValue, + imageAlt, + imageSize, + fileType, + fileName, + setShowAddIcon, + showAddIcon, + }) => { + const t = useTranslations(); + const fileInputRef = useRef(null); + + const handleClick = () => { + fileInputRef.current.click(); + }; + + const handleDeleteImage = () => { + setselectedImage(null); + setFieldValue(fieldname, null); + setShowAddIcon(true); + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + }; + + const isDocumentFormat = (fileType) => { + const documentFormats = [ + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ]; + return documentFormats.includes(fileType); + }; + + return ( + + {showAddIcon ? ( + // Show the add icon and "Upload File" text when no image is selected + <> + + + + {t("UploadSystem.upload_file")} + + + + ) : ( + // Show the uploaded content along with the delete button when an image or document is selected + <> + {fileType && fileType.startsWith("image/") ? ( + + + + ) : ( + fileType && + isDocumentFormat(fileType) && ( + + + {fileName} + + + ) + )} + + + )} + + + ); +}; + +export default UploadSystem; diff --git a/src/core/components/isBotHandler.jsx b/src/core/components/isBotHandler.jsx deleted file mode 100644 index 0fde3e3..0000000 --- a/src/core/components/isBotHandler.jsx +++ /dev/null @@ -1,8 +0,0 @@ -import { NoSsr } from "@mui/material"; - -const NoSsrHandler = ({ isBot, children }) => { - if (isBot) return children; - return {children}; -}; - -export default NoSsrHandler; diff --git a/src/core/components/notifications/ErrorNotification.jsx b/src/core/components/notifications/ErrorNotification.jsx new file mode 100644 index 0000000..4ff1ab0 --- /dev/null +++ b/src/core/components/notifications/ErrorNotification.jsx @@ -0,0 +1,39 @@ +import DangerousIcon from "@mui/icons-material/Dangerous"; +import {Box, Typography} from "@mui/material"; +import {toast} from "react-toastify"; + +const ErrorNotification = (t, status, message) => { + toast( + () => ( + <> + + + + + + {t("notifications.error")} ({t("notifications.code")}: {status}) + + + {message || t("notifications.error_static_text")} + + + + + + ), + { + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); +}; + +export default ErrorNotification; diff --git a/src/core/components/notifications/PendingNotification.jsx b/src/core/components/notifications/PendingNotification.jsx new file mode 100644 index 0000000..846b847 --- /dev/null +++ b/src/core/components/notifications/PendingNotification.jsx @@ -0,0 +1,12 @@ +import {toast} from "react-toastify"; + +const PendingNotification = (t) => { + toast(t("notifications.pending"), { + autoClose: false, + closeButton: false, + closeOnClick: false, + draggable: false, + }); +}; + +export default PendingNotification; diff --git a/src/core/components/notifications/SuccessNotification.jsx b/src/core/components/notifications/SuccessNotification.jsx new file mode 100644 index 0000000..998deaa --- /dev/null +++ b/src/core/components/notifications/SuccessNotification.jsx @@ -0,0 +1,42 @@ +import BeenhereIcon from "@mui/icons-material/Beenhere"; +import {Box, Typography} from "@mui/material"; +import {toast} from "react-toastify"; + +const SuccessNotification = (t, status) => { + toast( + () => ( + <> + + + + + + {t("notifications.success")} ({t("notifications.code")}:{" "} + {status}) + + + {t("notifications.success_static_text")} + + + + + + ), + { + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); +}; + +export default SuccessNotification; diff --git a/src/core/components/notifications/UploadFileNotification.jsx b/src/core/components/notifications/UploadFileNotification.jsx new file mode 100644 index 0000000..6556944 --- /dev/null +++ b/src/core/components/notifications/UploadFileNotification.jsx @@ -0,0 +1,38 @@ +import DangerousIcon from "@mui/icons-material/Dangerous"; +import {Box, Typography} from "@mui/material"; +import {toast} from "react-toastify"; + +const UploadFileNotification = (t) => { + toast( + ({closeToast}) => ( + <> + + + + + + {t("UploadSystem.uploadfile_error")} + + + + + + ), + { + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); +}; + +export default UploadFileNotification; diff --git a/src/core/components/notifications/WarningNotification.jsx b/src/core/components/notifications/WarningNotification.jsx new file mode 100644 index 0000000..8493180 --- /dev/null +++ b/src/core/components/notifications/WarningNotification.jsx @@ -0,0 +1,40 @@ +import ReportIcon from "@mui/icons-material/Report"; +import {Box, Typography} from "@mui/material"; +import {toast} from "react-toastify"; + +const WarningNotification = (t, status) => { + toast( + () => ( + <> + + + + + + {t("notifications.warning")} ({t("notifications.code")}:{" "} + {status}) + + + {t("notifications.warning_static_text")} + + + + + + ), + { + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); +}; + +export default WarningNotification; diff --git a/src/core/components/notifications/index.jsx b/src/core/components/notifications/index.jsx new file mode 100644 index 0000000..bc8eb66 --- /dev/null +++ b/src/core/components/notifications/index.jsx @@ -0,0 +1,54 @@ +import {toast} from "react-toastify"; +import ErrorNotification from "./ErrorNotification"; +import WarningNotification from "./WarningNotification"; +import SuccessNotification from "./SuccessNotification"; + +const Notifications = async (t, response) => { + const {status, data} = response != undefined ? response : "" + toast.dismiss(); + switch (status) { + case 200: + SuccessNotification(t, status); + break; + case 400: + ErrorNotification(t, status); + break; + case 401: + ErrorNotification(t, status); + break; + case 403: + ErrorNotification(t, status); + break; + case 422: + ErrorNotification(t, status, data.message); + break; + case 500: + WarningNotification(t, status); + break; + case 503: + WarningNotification(t, status); + break; + case 504: + WarningNotification(t, status); + break; + default: + toast(t("notifications.pending"), { + autoClose: false, + closeOnClick: false, + draggable: false, + }); + break; + } +}; + +export default Notifications; + +/* +usage document + +** for pending use ( Notifications( t, undefined) ) this before your request. +** for success use ( Notifications( t, response) ) this inside .then() of your request. +** for Error and Warning use ( Notifications( t, error.response) ) this inside .catche() of your request. + +end usage document +*/ diff --git a/src/core/components/svgs/Svg403.jsx b/src/core/components/svgs/Svg403.jsx new file mode 100644 index 0000000..720828c --- /dev/null +++ b/src/core/components/svgs/Svg403.jsx @@ -0,0 +1,131 @@ +import {useTheme} from "@mui/material"; + +const Svg403 = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} + +export default Svg403 \ No newline at end of file diff --git a/src/core/components/svgs/Svg404.jsx b/src/core/components/svgs/Svg404.jsx new file mode 100644 index 0000000..e46ab12 --- /dev/null +++ b/src/core/components/svgs/Svg404.jsx @@ -0,0 +1,101 @@ +import {useTheme} from "@mui/material"; + +const Svg404 = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default Svg404 \ No newline at end of file diff --git a/src/core/components/svgs/SvgChangePassword.jsx b/src/core/components/svgs/SvgChangePassword.jsx new file mode 100644 index 0000000..a7ee82f --- /dev/null +++ b/src/core/components/svgs/SvgChangePassword.jsx @@ -0,0 +1,77 @@ +import {useTheme} from "@mui/material"; + +const SvgChangePassword = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default SvgChangePassword \ No newline at end of file diff --git a/src/core/components/svgs/SvgDashboard.jsx b/src/core/components/svgs/SvgDashboard.jsx new file mode 100644 index 0000000..a5b40e0 --- /dev/null +++ b/src/core/components/svgs/SvgDashboard.jsx @@ -0,0 +1,117 @@ +import {useTheme} from "@mui/material"; + +const SvgDashboard = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default SvgDashboard \ No newline at end of file diff --git a/src/core/components/svgs/SvgLoading.jsx b/src/core/components/svgs/SvgLoading.jsx new file mode 100644 index 0000000..f9cea4a --- /dev/null +++ b/src/core/components/svgs/SvgLoading.jsx @@ -0,0 +1,136 @@ +import {useTheme} from "@mui/material"; + +const SvgLoading = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default SvgLoading \ No newline at end of file diff --git a/src/core/components/svgs/SvgLogin.jsx b/src/core/components/svgs/SvgLogin.jsx new file mode 100644 index 0000000..643c195 --- /dev/null +++ b/src/core/components/svgs/SvgLogin.jsx @@ -0,0 +1,75 @@ +import {useTheme} from "@mui/material"; + +const SvgLogin = ({width, height}) => { + const theme = useTheme() + const fillColor = theme.palette.primary.main + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} + +export default SvgLogin \ No newline at end of file diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js index e69de29..e430c68 100644 --- a/src/core/data/apiRoutes.js +++ b/src/core/data/apiRoutes.js @@ -0,0 +1,135 @@ +const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; + +//login +export const GET_USER_TOKEN = BASE_URL + "/dashboard/login"; +//end login + +//change password +export const SET_USER_PASSWORD = BASE_URL + "/dashboard/profile/change_password"; +//end change password + +//user data +export const GET_USER_ROUTE = BASE_URL + "/dashboard/profile/info"; +//user data + +//passenger office +export const GET_PASSENGER_OFFICE = + BASE_URL + "/dashboard/passenger_office_chief/show"; + +export const CONFIRM_PASSENGER_OFFICE = + BASE_URL + "/dashboard/passenger_office_chief/confirm"; + +export const REJECT_PASSENGER_OFFICE = + BASE_URL + "/dashboard/passenger_office_chief/reject"; +//passenger office + +//passenger boss +export const GET_PASSENGER_BOSS = + BASE_URL + "/dashboard/province_working_group/show"; + +export const CONFIRM_PASSENGER_BOSS = + BASE_URL + "/dashboard/province_working_group/confirm"; + +export const REJECT_PASSENGER_BOSS = + BASE_URL + "/dashboard/province_working_group/reject"; +//passenger boss + +//transportation assistance +export const GET_TRANSPORTATION_ASSISTANCE = + BASE_URL + "/dashboard/transportation_assistant/show"; + +export const CONFIRM_TRANSPORTATION_ASSISTANCE = + BASE_URL + "/dashboard/transportation_assistant/confirm"; + +export const REJECT_TRANSPORTATION_ASSISTANCE = + BASE_URL + "/dashboard/transportation_assistant/reject"; +//transportation assistance + +//machinary office +export const GET_MACHINARY_OFFICE = + BASE_URL + "/dashboard/machinery_expert/show"; + +export const CONFIRM_MACHINARY_OFFICE = + BASE_URL + "/dashboard/machinery_expert/confirm"; + +export const REJECT_MACHINARY_OFFICE = + BASE_URL + "/dashboard/machinery_expert/reject"; +//machinary office + +//commercial chief +export const GET_COMMERCIAL_CHIEF = + BASE_URL + "/dashboard/commercial_chief/show"; + +export const CONFIRM_COMMERCIAL_CHIEF = + BASE_URL + "/dashboard/commercial_chief/confirm"; + +export const REJECT_COMMERCIAL_CHIEF = + BASE_URL + "/dashboard/commercial_chief/reject"; +//commercial chief + +//navgan province manager +export const GET_NAVGAN_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/show"; + +export const CONFIRM_NAVGAN_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/confirm"; + +export const REJECT_NAVGAN_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/reject"; +//navgan province manager + +// refahi province manager +export const GET_REFAHI_PROVINCE_MANAGER = + BASE_URL + "/dashboard/refahi_province_manager/show"; + +export const CONFIRM_REFAHI_PROVINCE_MANAGER = + BASE_URL + "/dashboard/refahi_province_manager/confirm"; + +export const REJECT_REFAHI_PROVINCE_MANAGER = + BASE_URL + "/dashboard/refahi_province_manager/reject"; +//refahi province manager + +// development assistant +export const GET_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/show"; + +export const CONFIRM_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/confirm"; + +export const REJECT_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/reject"; +//development assistant + +// inspector expert +export const GET_INSPECTOR_EXPERT = + BASE_URL + "/dashboard/inspector_expert/show"; + +export const CONFIRM_INSPECTOR_EXPERT = + BASE_URL + "/dashboard/inspector_expert/confirm"; + +export const REJECT_INSPECTOR_EXPERT = + BASE_URL + "/dashboard/inspector_expert/reject"; + +export const REVISE_INSPECTOR_EXPERT = + BASE_URL + "/dashboard/inspector_expert/revise" +//inspector expert + +// province head expert +export const GET_PROVINCE_HEAD_EXPERT = + BASE_URL + "/dashboard/province_head_expert/show"; + +export const CONFIRM_PROVINCE_HEAD_EXPERT = + BASE_URL + "/dashboard/province_head_expert/confirm"; + +export const REJECT_PROVINCE_HEAD_EXPERT = + BASE_URL + "/dashboard/province_head_expert/reject"; + +export const REVISE_PROVINCE_HEAD_EXPERT = + BASE_URL + "/dashboard/province_head_expert/revise"; +//province head expert + +//sidebar notification +export const GET_SIDEBAR_NOTIFICATION = + BASE_URL + "/dashboard/notification" +//sidebar notification + diff --git a/src/core/data/headerProfileItems.jsx b/src/core/data/headerProfileItems.jsx index 63e661a..577fba3 100644 --- a/src/core/data/headerProfileItems.jsx +++ b/src/core/data/headerProfileItems.jsx @@ -2,18 +2,18 @@ import BorderColorIcon from "@mui/icons-material/BorderColor"; import PasswordIcon from "@mui/icons-material/Password"; const headerProfileItems = [ - { - key: 0, - name: "header.edit_profile", - route: "/dashboard/edit-profile", - icon: , - }, - { - key: 1, - name: "header.change_password", - route: "/dashboard/change-password", - icon: , - }, + { + key: 0, + name: "header.edit_profile", + route: "/dashboard/edit-profile", + icon: , + }, + { + key: 1, + name: "header.change_password", + route: "/dashboard/change-password", + icon: , + }, ]; export default headerProfileItems; diff --git a/src/core/data/sidebarMenu.jsx b/src/core/data/sidebarMenu.jsx index c8e6ed8..c2dc246 100644 --- a/src/core/data/sidebarMenu.jsx +++ b/src/core/data/sidebarMenu.jsx @@ -1,17 +1,121 @@ import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; -import BookmarkAddedIcon from "@mui/icons-material/BookmarkAdded"; -import DataSaverOnIcon from "@mui/icons-material/DataSaverOn"; +import DirectionsCarFilledIcon from "@mui/icons-material/DirectionsCarFilled"; +import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; +import DirectionsRailwayIcon from "@mui/icons-material/DirectionsRailway"; +import AssignmentIndIcon from "@mui/icons-material/AssignmentInd"; +import DesktopWindowsIcon from "@mui/icons-material/DesktopWindows"; +import GavelIcon from '@mui/icons-material/Gavel'; +import BusinessCenterIcon from '@mui/icons-material/BusinessCenter'; +import GradingIcon from '@mui/icons-material/Grading'; +import SupervisedUserCircleIcon from '@mui/icons-material/SupervisedUserCircle'; +import Diversity3Icon from '@mui/icons-material/Diversity3'; const sidebarMenu = [ - [ - { - key: "sidebar.dashboard", - type: "page", - route: "/dashboard", - icon: , - selected: false, - }, - ], + [ + { + key: "sidebar.dashboard", + type: "page", + route: "/dashboard", + icon: , + selected: false, + permission: "all", + }, + { + key: "sidebar.passenger-office-chief", + secondary: "secondary.passenger-office", + name: "passenger_office_chief", + type: "page", + route: "/dashboard/passenger-office-chief", + icon: , + selected: false, + permission: "manage_passenger_office_navgan", + }, + { + key: "sidebar.machinery-expert", + name: "machinery_expert", + type: "page", + route: "/dashboard/machinery-expert", + icon: , + selected: false, + permission: "manage_machinery_navgan", + }, + { + key: "sidebar.passenger-boss", + secondary: "secondary.passenger-boss", + name: "province_working_group", + type: "page", + route: "/dashboard/passenger-boss", + icon: , + selected: false, + permission: "manage_province_working_group_navgan", + }, + + { + key: "sidebar.transportation-assistant", + name: "transportation_assistant", + type: "page", + route: "/dashboard/transportation-assistant", + icon: , + selected: false, + permission: "manage_transportation_navgan", + }, + { + key: "sidebar.navgan-province-manager", + secondary: "secondary.navgan-province-manager", + name: "province_manager_navgan", + type: "page", + route: "/dashboard/navgan-province-manager", + icon: , + selected: false, + permission: "manage_province_affairs_navgan", + }, + { + key: "sidebar.province-head-expert", + name: "province_head_expert", + type: "page", + route: "/dashboard/province-head-expert", + icon: , + selected: false, + permission: "manage_province_headquarter_refahi", + }, + { + key: "sidebar.inspector-expert", + name: "inspector_expert", + type: "page", + route: "/dashboard/inspector-expert", + icon: , + selected: false, + permission: "manage_inspector_refahi", + }, + { + key: "sidebar.commercial-chief", + name: "commercial_chief", + type: "page", + route: "/dashboard/commercial-chief", + icon: , + selected: false, + permission: "manage_commercial_refahi", + }, + { + key: "sidebar.development-assistant", + name: "development_assistant", + type: "page", + route: "/dashboard/development-assistant", + icon: , + selected: false, + permission: "manage_development_refahi", + }, + { + key: "sidebar.refahi-province-manager", + secondary: "secondary.refahi-province-manager", + name: "province_manager_refahi", + type: "page", + route: "/dashboard/refahi-province-manager", + icon: , + selected: false, + permission: "manage_province_affairs_refahi", + }, + ], ]; export default sidebarMenu; diff --git a/src/core/utils/createEmotionCache.jsx b/src/core/utils/createEmotionCache.jsx index 06add02..413fafe 100644 --- a/src/core/utils/createEmotionCache.jsx +++ b/src/core/utils/createEmotionCache.jsx @@ -1,38 +1,38 @@ import createCache from "@emotion/cache"; -import { prefixer } from "stylis"; +import {prefixer} from "stylis"; import stylisRTLPlugin from "stylis-plugin-rtl"; const isBrowser = typeof document !== "undefined"; export const createEmotionCacheLtr = () => { - let insertionPoint; + let insertionPoint; - if (isBrowser) { - const emotionInsertionPoint = document.querySelector( - 'meta[name="emotion-insertion-point"]' - ); - insertionPoint = emotionInsertionPoint ?? undefined; - } + if (isBrowser) { + const emotionInsertionPoint = document.querySelector( + 'meta[name="emotion-insertion-point"]' + ); + insertionPoint = emotionInsertionPoint ?? undefined; + } - return createCache({ - key: "mui-style", - insertionPoint, - }); + return createCache({ + key: "mui-style", + insertionPoint, + }); }; export const createEmotionCacheRtl = () => { - let insertionPoint; + let insertionPoint; - if (isBrowser) { - const emotionInsertionPoint = document.querySelector( - 'meta[name="emotion-insertion-point"]' - ); - insertionPoint = emotionInsertionPoint ?? undefined; - } + if (isBrowser) { + const emotionInsertionPoint = document.querySelector( + 'meta[name="emotion-insertion-point"]' + ); + insertionPoint = emotionInsertionPoint ?? undefined; + } - return createCache({ - key: "muirtl", - stylisPlugins: [prefixer, stylisRTLPlugin], - insertionPoint, - }); + return createCache({ + key: "muirtl", + stylisPlugins: [prefixer, stylisRTLPlugin], + insertionPoint, + }); }; diff --git a/src/core/utils/errorHandler.js b/src/core/utils/errorHandler.js new file mode 100644 index 0000000..9bd18f1 --- /dev/null +++ b/src/core/utils/errorHandler.js @@ -0,0 +1,62 @@ +import ErrorNotification from "@/core/components/notifications/ErrorNotification"; +import WarningNotification from "@/core/components/notifications/WarningNotification"; +import {toast} from "react-toastify"; + +export const errorSetting = (t, notification) => { + if (notification) toast.dismiss(); +} + +export const errorRequest = (t, notification) => { + if (notification) toast.dismiss(); +} + +export const errorResponse = (response, clearToken, t, notification) => { + if (notification) toast.dismiss(); + if (isServerError(response.status)) { + errorServer(response, t, notification) + } else if (isClientError(response.status)) { + errorClient(response, clearToken, t, notification) + } +} + +const errorServer = (response, t, notification) => { + if (notification) WarningNotification(t, response.status); +} +const errorClient = (response, clearToken, t, notification) => { + switch (response.status) { + case 401: + clearToken() + if (notification) ErrorNotification(t, response.status) + break; + case 422: + if ('type' in response.data) { + errorLogic(response, t, notification) + break; + } + errorValidation(response, t, notification) + break; + case 429: + if (notification) ErrorNotification(t, response.status) + break + default: + if (notification) ErrorNotification(t, response.status) + break + } +} + +const isServerError = status => status >= 500 && status <= 599; +const isClientError = status => status >= 400 && status <= 499; + +const errorLogic = (response, t, notification) => { + if (notification) ErrorNotification(t, response.status) +} +const errorValidation = (response, t, notification) => { + if (notification) { + const errorsMap = Object.keys(response.data.errors) + const errorsArray = response.data.errors + + errorsMap.map((item, index) => { + ErrorNotification(t, response.status, errorsArray[item][0]); + }) + } +} \ No newline at end of file diff --git a/src/core/utils/succesHandler.js b/src/core/utils/succesHandler.js new file mode 100644 index 0000000..a61ac85 --- /dev/null +++ b/src/core/utils/succesHandler.js @@ -0,0 +1,9 @@ +import SuccessNotification from "@/core/components/notifications/SuccessNotification"; +import {toast} from "react-toastify"; + +export const successRequest = (response, t, options) => { + if (options.notification && options.success.notification.show) { + toast.dismiss(); + SuccessNotification(t, response.status) + } +} \ No newline at end of file diff --git a/src/core/utils/theme-rtl.jsx b/src/core/utils/theme-rtl.jsx index c36abeb..33a9ae7 100644 --- a/src/core/utils/theme-rtl.jsx +++ b/src/core/utils/theme-rtl.jsx @@ -1,12 +1,14 @@ -import { createTheme } from "@mui/material/styles"; +import {createTheme} from "@mui/material/styles"; import theme from "./theme"; +import {faIR} from "@mui/x-date-pickers/locales"; const themeRtl = createTheme({ - direction: "rtl", - typography: { - fontFamily: `IRANSans, sans-serif`, - }, - ...theme, + direction: "rtl", + typography: { + fontFamily: `IRANSansFaNum, sans-serif`, + }, + faIR, + ...theme, }); export default themeRtl; diff --git a/src/core/utils/theme.jsx b/src/core/utils/theme.jsx index 0a36eee..672e8a8 100644 --- a/src/core/utils/theme.jsx +++ b/src/core/utils/theme.jsx @@ -1,18 +1,29 @@ +import {colord} from "colord"; + const theme = { - palette: { - primary: { - main: "#084070", - contrastText: "#fff", - light: "#2c6291", - dark: "#11293e", + palette: { + primary: { + main: process.env.NEXT_PUBLIC_PRIMARY_MAIN, + contrastText: "#FFFFFF", + light: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).lighten(0.1).toHex(), + dark: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).darken(0.1).toHex(), + }, + secondary: { + main: process.env.NEXT_PUBLIC_SECONDARY_MAIN, + contrastText: "#FFFFFF", + light: colord(process.env.NEXT_PUBLIC_SECONDARY_MAIN).lighten(0.1).toHex(), + dark: colord(process.env.NEXT_PUBLIC_SECONDARY_MAIN).darken(0.1).toHex(), + }, }, - secondary: { - main: "#FF4E00", - contrastText: "#fff", - light: "#ed743e", - dark: "#ad3a07", + components: { + MuiBackdrop: { + styleOverrides: { + root: { + backgroundColor: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).darken(0.2).alpha(0.7).toHex(), + }, + }, + }, }, - }, }; export default theme; diff --git a/src/layouts/AppLayout.jsx b/src/layouts/AppLayout.jsx index 2f7988e..4fc5e1d 100644 --- a/src/layouts/AppLayout.jsx +++ b/src/layouts/AppLayout.jsx @@ -1,85 +1,56 @@ import theme from "@/core/utils/theme"; +import useLanguage from "@/lib/app/hooks/useLanguage"; import useLoading from "@/lib/app/hooks/useLoading"; import useUser from "@/lib/app/hooks/useUser"; -import Head from "next/head"; import NextNProgress from "nextjs-progressbar"; -import { useEffect } from "react"; +import {useEffect} from "react"; +import {ToastContainer} from "react-toastify"; +import useDirection from "@/lib/app/hooks/useDirection"; +import "react-toastify/dist/ReactToastify.css"; +import NetworkComponent from "@/core/components/NetworkComponent"; +import GlobalHead from "@/core/components/GlobalHead"; -function AppLayout({ children, isBot }) { - const { setLoadingPage } = useLoading(); - const { token, isAuth } = useUser(); - useEffect(() => { - if (token) { - if (isAuth) { - setLoadingPage(false); - return; +function AppLayout({children, isBot}) { + const {languageIsReady} = useLanguage(); + const {setLoadingPage} = useLoading(); + const {userChangedLanguage, token, isAuth} = useUser(); + const {directionApp} = useDirection(); + + useEffect(() => { + if (languageIsReady) { + if (token) { + if (isAuth) { + if (userChangedLanguage) { + setLoadingPage(true); + return; + } + setLoadingPage(false); + return; + } + setLoadingPage(true); + return; + } + setLoadingPage(false); + return; } setLoadingPage(true); - return; - } - setLoadingPage(false); - return; - }, [token, isAuth]); + }, [languageIsReady, token, isAuth, userChangedLanguage]); - return ( - <> - - + + - - - - - - - - - - - - - - - - - - - - {children} - - ); + + + {children} + ); } export default AppLayout; diff --git a/src/layouts/CenterLayout.jsx b/src/layouts/CenterLayout.jsx index 4c8767f..1e1b8bf 100644 --- a/src/layouts/CenterLayout.jsx +++ b/src/layouts/CenterLayout.jsx @@ -1,18 +1,18 @@ -import { Fade, Stack } from "@mui/material"; +import {Fade, Stack} from "@mui/material"; const CenterLayout = (props) => { - return ( - - - {props.children} - - - ); + return ( + + + {props.children} + + + ); }; export default CenterLayout; diff --git a/src/layouts/FullPageLayout.jsx b/src/layouts/FullPageLayout.jsx index cbf2102..d6ed61e 100644 --- a/src/layouts/FullPageLayout.jsx +++ b/src/layouts/FullPageLayout.jsx @@ -1,21 +1,21 @@ -import { Stack } from "@mui/material"; +import {Stack} from "@mui/material"; const FullPageLayout = (props) => { - return ( - - {props.children} - - ); + return ( + + {props.children} + + ); }; export default FullPageLayout; diff --git a/src/layouts/MuiLayout.jsx b/src/layouts/MuiLayout.jsx index ba891d0..6dcd3ed 100644 --- a/src/layouts/MuiLayout.jsx +++ b/src/layouts/MuiLayout.jsx @@ -1,76 +1,73 @@ -import NoSsrHandler from "@/core/components/isBotHandler"; -import { - createEmotionCacheRtl -} from "@/core/utils/createEmotionCache"; +import NoSsrHandler from "@/core/components/NoSsrHandler"; +import {createEmotionCacheRtl} from "@/core/utils/createEmotionCache"; import themeRtl from "@/core/utils/theme-rtl"; -import { CacheProvider } from "@emotion/react"; -import { GlobalStyles } from "@mui/material"; +import {CacheProvider} from "@emotion/react"; +import {GlobalStyles} from "@mui/material"; import CssBaseline from "@mui/material/CssBaseline"; -import { ThemeProvider } from "@mui/material/styles"; +import {ThemeProvider} from "@mui/material/styles"; import Head from "next/head"; const clientSideEmotionCacheRtl = createEmotionCacheRtl(); -const MuiLayout = ({ children, isBot }) => { +const MuiLayout = ({children, isBot}) => { + const emotionCache = clientSideEmotionCacheRtl; + const theme = themeRtl; - const emotionCache = clientSideEmotionCacheRtl; + return ( + + + + + + + - - - - - - - body: { - width: "100vw", - height: "100vh", - }, - "#__next": { - width: "100%", - height: "100%", - }, - }} - /> - - - {children} - - - - ); + + {children} + + + + ); }; export default MuiLayout; diff --git a/src/layouts/ScrollableLayout.jsx b/src/layouts/ScrollableLayout.jsx index 5ab58ca..583edd7 100644 --- a/src/layouts/ScrollableLayout.jsx +++ b/src/layouts/ScrollableLayout.jsx @@ -1,25 +1,25 @@ -import { Box, Fade } from "@mui/material"; +import {Box, Fade} from "@mui/material"; const ScrollableLayout = (props) => { - const overflowY = props?.y || "hidden"; - const overflowX = props?.x || "hidden"; + const overflowY = props?.y || "hidden"; + const overflowX = props?.x || "hidden"; - return ( - - - {props.children} - - - ); + return ( + + + {props.children} + + + ); }; export default ScrollableLayout; diff --git a/src/layouts/dashboardLayouts/breadcrumbs/BreadcrumbItem.jsx b/src/layouts/dashboardLayouts/breadcrumbs/BreadcrumbItem.jsx index ccff4c9..c233be3 100644 --- a/src/layouts/dashboardLayouts/breadcrumbs/BreadcrumbItem.jsx +++ b/src/layouts/dashboardLayouts/breadcrumbs/BreadcrumbItem.jsx @@ -1,19 +1,19 @@ import LinkRouting from "@/core/components/LinkRouting"; -import { Typography } from "@mui/material"; -import { useTranslations } from "next-intl"; +import {Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; export default function BreadcrumbItem(props) { - const t = useTranslations(); - const isLast = props.index === props.RouterArray.length - 1; - const url = `/${props.RouterArray.slice(0, props.index + 1).join("/")}`; + const t = useTranslations(); + const isLast = props.index === props.RouterArray.length - 1; + const url = `/${props.RouterArray.slice(0, props.index + 1).join("/")}`; - return isLast ? ( - - {t("sidebar." + props.label)} - - ) : ( - - {t("sidebar." + props.label)} - - ); + return isLast ? ( + + {t("sidebar." + props.label)} + + ) : ( + + {t("sidebar." + props.label)} + + ); } diff --git a/src/layouts/dashboardLayouts/breadcrumbs/index.jsx b/src/layouts/dashboardLayouts/breadcrumbs/index.jsx index 3123a12..9ab234e 100644 --- a/src/layouts/dashboardLayouts/breadcrumbs/index.jsx +++ b/src/layouts/dashboardLayouts/breadcrumbs/index.jsx @@ -1,49 +1,49 @@ -import { useRouter } from "next/router"; -import { Box, Breadcrumbs } from "@mui/material"; -import { useTheme } from "@mui/material/styles"; -import { NavigateBefore, NavigateNext } from "@mui/icons-material"; +import {useRouter} from "next/router"; +import {Box, Breadcrumbs} from "@mui/material"; +import {useTheme} from "@mui/material/styles"; +import {NavigateBefore, NavigateNext} from "@mui/icons-material"; import BreadcrumbItem from "./BreadcrumbItem"; const BreadCrumbs = (props) => { - const { isVisible } = props; - const theme = useTheme(); - const router = useRouter(); + const {isVisible} = props; + const theme = useTheme(); + const router = useRouter(); - if (!isVisible) { - return null; - } + if (!isVisible) { + return null; + } - const { pathname } = router; - const RouterArray = pathname.split("/").filter((segment) => segment !== ""); + const {pathname} = router; + const RouterArray = pathname.split("/").filter((segment) => segment !== ""); - if (RouterArray.length === 1) { - return null; - } + if (RouterArray.length === 1) { + return null; + } - return ( - - - ) : ( - - ) - } - aria-label="breadcrumb" - > - {RouterArray.map((segment, index) => ( - - ))} - - - ); + return ( + + + ) : ( + + ) + } + aria-label="breadcrumb" + > + {RouterArray.map((segment, index) => ( + + ))} + + + ); }; export default BreadCrumbs; diff --git a/src/layouts/dashboardLayouts/header/ProfileData.jsx b/src/layouts/dashboardLayouts/header/ProfileData.jsx index c3fdf58..548378b 100644 --- a/src/layouts/dashboardLayouts/header/ProfileData.jsx +++ b/src/layouts/dashboardLayouts/header/ProfileData.jsx @@ -1,18 +1,18 @@ -import { Avatar, Stack, Typography } from "@mui/material"; +import {Avatar, Stack, Typography} from "@mui/material"; import useUser from "@/lib/app/hooks/useUser"; export default function ProfileData() { - const { user } = useUser(); - return ( - - - - {user.user_username} - - - ); + const {user} = useUser(); + return ( + + + + {user.username} + + + ); } diff --git a/src/layouts/dashboardLayouts/header/ProfileMenu.jsx b/src/layouts/dashboardLayouts/header/ProfileMenu.jsx index 50f34db..415d501 100644 --- a/src/layouts/dashboardLayouts/header/ProfileMenu.jsx +++ b/src/layouts/dashboardLayouts/header/ProfileMenu.jsx @@ -1,61 +1,62 @@ -import { Avatar, Menu, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; +import {Avatar, IconButton, Menu, Tooltip} from "@mui/material"; +import {useState} from "react"; import ProfileData from "./ProfileData"; import ProfileOptions from "./ProfileOptions"; -import { useTranslations } from "next-intl"; +import {useTranslations} from "next-intl"; import useUser from "@/lib/app/hooks/useUser"; function ProfileMenu() { - const t = useTranslations(); - const [anchorElUser, setAnchorElUser] = useState(null); - const { user } = useUser(); + const t = useTranslations(); + const [anchorElUser, setAnchorElUser] = useState(null); + const {user} = useUser(); - const handleOpenUserMenu = (event) => { - setAnchorElUser(event.currentTarget); - }; - const handleCloseUserMenu = () => { - setAnchorElUser(null); - }; + const handleOpenUserMenu = (event) => { + setAnchorElUser(event.currentTarget); + }; + const handleCloseUserMenu = () => { + setAnchorElUser(null); + }; - return ( - <> - - - - - - - - - - - ); + return ( + <> + + + + + + + + + + + ); } + export default ProfileMenu; diff --git a/src/layouts/dashboardLayouts/header/ProfileOptionLogOut.jsx b/src/layouts/dashboardLayouts/header/ProfileOptionLogOut.jsx index f56db6c..2a6cf85 100644 --- a/src/layouts/dashboardLayouts/header/ProfileOptionLogOut.jsx +++ b/src/layouts/dashboardLayouts/header/ProfileOptionLogOut.jsx @@ -1,49 +1,49 @@ -import { Box, Button, MenuItem, Typography } from "@mui/material"; +import {Box, Button, MenuItem, Typography} from "@mui/material"; import MeetingRoomIcon from "@mui/icons-material/MeetingRoom"; import useUser from "@/lib/app/hooks/useUser"; -import { useTranslations } from "next-intl"; +import {useTranslations} from "next-intl"; -export default function ProfileOptionLogOut({ handleCloseUserMenu }) { - const t = useTranslations(); - const { clearToken } = useUser(); - const handleClickLogOut = () => { - handleCloseUserMenu(); - clearToken(); - }; - return ( - <> - - - - - - - {t("header.logout")} - - - - - ); +export default function ProfileOptionLogOut({handleCloseUserMenu}) { + const t = useTranslations(); + const {clearToken} = useUser(); + const handleClickLogOut = () => { + handleCloseUserMenu(); + clearToken(); + }; + return ( + <> + + + + + + + {t("header.logout")} + + + + + ); } diff --git a/src/layouts/dashboardLayouts/header/ProfileOptions.jsx b/src/layouts/dashboardLayouts/header/ProfileOptions.jsx index bf63212..6e7bdba 100644 --- a/src/layouts/dashboardLayouts/header/ProfileOptions.jsx +++ b/src/layouts/dashboardLayouts/header/ProfileOptions.jsx @@ -1,49 +1,49 @@ -import { Box, MenuItem, Typography } from "@mui/material"; -import { NextLinkComposed } from "@/core/components/LinkRouting"; -import { useTranslations } from "next-intl"; +import {Box, MenuItem, Typography} from "@mui/material"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; +import {useTranslations} from "next-intl"; import headerProfileItems from "@/core/data/headerProfileItems"; import ProfileOptionLogOut from "./ProfileOptionLogOut"; -export default function ProfileOptions({ handleCloseUserMenu }) { - const t = useTranslations(); +export default function ProfileOptions({handleCloseUserMenu}) { + const t = useTranslations(); - return ( - <> - {headerProfileItems.map((profile_item) => ( - - - - {profile_item.icon} - - - {t(profile_item.name)} - - - - ))} - - - ); + return ( + <> + {headerProfileItems.map((profile_item) => ( + + + + {profile_item.icon} + + + {t(profile_item.name)} + + + + ))} + + + ); } diff --git a/src/layouts/dashboardLayouts/header/index.jsx b/src/layouts/dashboardLayouts/header/index.jsx index cd1e4a0..8760960 100644 --- a/src/layouts/dashboardLayouts/header/index.jsx +++ b/src/layouts/dashboardLayouts/header/index.jsx @@ -1,80 +1,72 @@ import MenuIcon from "@mui/icons-material/Menu"; -import { - AppBar, - Box, - Container, - CssBaseline, - IconButton, - Stack, - Toolbar, - useTheme -} from "@mui/material"; +import {AppBar, Box, Container, CssBaseline, IconButton, Stack, Toolbar, useTheme} from "@mui/material"; import ProfileMenu from "./ProfileMenu"; -function Header({ drawerWidth, handleDrawerToggle }) { - const theme = useTheme(); +function Header({drawerWidth, handleDrawerToggle}) { + const theme = useTheme(); - return ( - <> - - - - - - - - - - - + + - - - - - - - - - - ); + > + + + + + + + + + + + + + + + + + + + ); } + export default Header; diff --git a/src/layouts/dashboardLayouts/index.jsx b/src/layouts/dashboardLayouts/index.jsx index f1478bf..fae51d2 100644 --- a/src/layouts/dashboardLayouts/index.jsx +++ b/src/layouts/dashboardLayouts/index.jsx @@ -1,50 +1,45 @@ -import { useState } from "react"; +import {useState} from "react"; import FullPageLayout from "../FullPageLayout"; import Header from "./header"; import Sidebar from "./sidebar"; -import { Toolbar } from "@mui/material"; +import {Toolbar} from "@mui/material"; import BreadCrumbs from "./breadcrumbs"; -import { ToastContainer } from "react-toastify"; -import "react-toastify/dist/ReactToastify.css"; -import useDirection from "@/lib/app/hooks/useDirection"; const drawerWidth = 240; const DashboardLayouts = (props) => { - const { directionApp } = useDirection(); - const { window } = props; - const [mobileOpen, setMobileOpen] = useState(false); - const container = - window !== undefined ? () => window().document.body : undefined; + const {window} = props; + const [mobileOpen, setMobileOpen] = useState(false); + const container = + window !== undefined ? () => window().document.body : undefined; - const handleDrawerToggle = () => { - setMobileOpen(!mobileOpen); - }; - return ( - -
- - - - - - {props.children} + const handleDrawerToggle = () => { + setMobileOpen(!mobileOpen); + }; + return ( + +
+ + + + + + {props.children} + + - - {directionApp === "rtl" ? : } - - ); + ); }; export default DashboardLayouts; diff --git a/src/layouts/dashboardLayouts/sidebar/SidebarDrawer.jsx b/src/layouts/dashboardLayouts/sidebar/SidebarDrawer.jsx index 6eb5e60..f155dce 100644 --- a/src/layouts/dashboardLayouts/sidebar/SidebarDrawer.jsx +++ b/src/layouts/dashboardLayouts/sidebar/SidebarDrawer.jsx @@ -1,29 +1,27 @@ -import { Divider, Stack, Toolbar, Typography } from "@mui/material"; -import { useTranslations } from "next-intl"; +import {Divider, Stack, Toolbar, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; import SidebarList from "./SidebarList"; -import StyledImage from "@/core/components/StyledImage"; +import useUser from "@/lib/app/hooks/useUser"; -const SidebarDrawer = ({ handleDrawerToggle }) => { - const t = useTranslations(); - return ( - <> - - - - {t("app_short_name")} - - - { - t("expert") /* make if on thease t("user_welfare_services") - t("user_navy") */ - } - - - - - - - ); +const SidebarDrawer = ({handleDrawerToggle}) => { + const {user} = useUser() + const t = useTranslations(); + return ( + <> + + + + {t("app_short_name")} + + + {user.name} | {user.position} + + + + + + + ); }; export default SidebarDrawer; diff --git a/src/layouts/dashboardLayouts/sidebar/SidebarList.jsx b/src/layouts/dashboardLayouts/sidebar/SidebarList.jsx index 79dd93e..a030b52 100644 --- a/src/layouts/dashboardLayouts/sidebar/SidebarList.jsx +++ b/src/layouts/dashboardLayouts/sidebar/SidebarList.jsx @@ -1,56 +1,57 @@ -import { Divider, List } from "@mui/material"; -import { Fragment, useEffect, useReducer } from "react"; +import {Divider, List} from "@mui/material"; +import {useEffect, useReducer} from "react"; import SidebarListItem from "./SidebarListItem"; import sidebarMenu from "@/core/data/sidebarMenu"; -import { useRouter } from "next/router"; +import {useRouter} from "next/router"; +import useUser from "@/lib/app/hooks/useUser"; function reducer(state, action) { - switch (action.type) { - case "COLLAPSE_MENU": - return state.map((itemsArr) => - itemsArr.map((item) => - action.key == item.key - ? { ...item, showSubItem: !item.showSubItem } - : item - ) - ); - case "SELECTED": - return state.map((itemsArr) => - itemsArr.map((item) => - action.route == item.route - ? { ...item, selected: true } - : { ...item, selected: false } - ) - ); - default: - throw new Error(); - } + switch (action.type) { + case "COLLAPSE_MENU": + return state.map((itemsArr) => + itemsArr.map((item) => + action.key == item.key + ? {...item, showSubItem: !item.showSubItem} + : item + ) + ); + case "SELECTED": + return state.map((itemsArr) => + itemsArr.map((item) => + action.route == item.route + ? {...item, selected: true} + : {...item, selected: false} + ) + ); + default: + throw new Error(); + } } -export default function SidebarList({ handleDrawerToggle }) { - const [itemMenu, dispatch] = useReducer(reducer, sidebarMenu); +export default function SidebarList({handleDrawerToggle}) { + const [itemMenu, dispatch] = useReducer(reducer, sidebarMenu); + const {user} = useUser(); + const router = useRouter(); - // activate current page in menu - const router = useRouter(); - useEffect(() => { - dispatch({ type: "SELECTED", route: router.pathname }); - }, [router.pathname]); + useEffect(() => { + dispatch({type: "SELECTED", route: router.pathname}); + }, [router.pathname]); - return ( - - {itemMenu.map((itemArr, index) => ( - - {itemArr.map((item) => ( - - ))} - - - ))} - - ); + const filteredItemMenu = itemMenu[0].filter( + (item) => user.permissions.includes(item.permission) || item.permission === "all" + ); + + return ( + + {filteredItemMenu.map((item, index) => ( + + ))} + {filteredItemMenu.length > 0 && } + + ); } diff --git a/src/layouts/dashboardLayouts/sidebar/SidebarListItem.jsx b/src/layouts/dashboardLayouts/sidebar/SidebarListItem.jsx index ba270a5..ebeb14c 100644 --- a/src/layouts/dashboardLayouts/sidebar/SidebarListItem.jsx +++ b/src/layouts/dashboardLayouts/sidebar/SidebarListItem.jsx @@ -1,64 +1,84 @@ -import { NextLinkComposed } from "@/core/components/LinkRouting"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; import ExpandLess from "@mui/icons-material/ExpandLess"; import ExpandMore from "@mui/icons-material/ExpandMore"; -import { - ListItem, - ListItemButton, - ListItemIcon, - ListItemText, -} from "@mui/material"; -import { useTranslations } from "next-intl"; -import { Fragment } from "react"; +import {Badge, IconButton, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography,} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {Fragment} from "react"; import SidebarListSubItem from "./SidebarListSubItem"; +import useNotification from "@/lib/app/hooks/useNotification"; -const SidebarListItem = ({ item, dispatch, handleDrawerToggle }) => { - const t = useTranslations(); +const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => { + const t = useTranslations(); + const {notification_count} = useNotification() - return ( - - - { - if (item.type == "menu") { - dispatch({ type: "COLLAPSE_MENU", key: item.key }); - } - handleDrawerToggle(); - }} - sx={{ - minHeight: 48, - }} - > - - {item.icon} - - + return ( + + + + + }> + { + if (item.type == "menu") { + dispatch({type: "COLLAPSE_MENU", key: item.key}); + } + handleDrawerToggle(); + }} + sx={{ + minHeight: 48, + }} - {item.type == "menu" && - (item.showSubItem ? : )} - - - {item.subItem && ( - - )} - - ); + > + + {item.icon} + + + {t(item.secondary)} + + ) : null + } + /> + + + {item.type == "menu" && + (item.showSubItem ? : )} + + + {item.subItem && ( + + )} + + ); }; export default SidebarListItem; diff --git a/src/layouts/dashboardLayouts/sidebar/SidebarListSubItem.jsx b/src/layouts/dashboardLayouts/sidebar/SidebarListSubItem.jsx index f960efb..3407081 100644 --- a/src/layouts/dashboardLayouts/sidebar/SidebarListSubItem.jsx +++ b/src/layouts/dashboardLayouts/sidebar/SidebarListSubItem.jsx @@ -1,54 +1,48 @@ -import { NextLinkComposed } from "@/core/components/LinkRouting"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; import InboxIcon from "@mui/icons-material/MoveToInbox"; -import { - Collapse, - List, - ListItemButton, - ListItemIcon, - ListItemText, -} from "@mui/material"; -import { useTranslations } from "next-intl"; -import { Fragment } from "react"; +import {Collapse, List, ListItemButton, ListItemIcon, ListItemText,} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {Fragment} from "react"; -const SidebarListSubItem = ({ item, handleDrawerToggle }) => { - const t = useTranslations(); +const SidebarListSubItem = ({item, handleDrawerToggle}) => { + const t = useTranslations(); - return ( - - - {item.subItem.map((subitem, index) => ( - - { - if (item.type == "menu") { - dispatch({ type: "COLLAPSE_MENU", key: item.key }); - } - handleDrawerToggle(); - }} - > - - - - - - - ))} - - - ); + return ( + + + {item.subItem.map((subitem, index) => ( + + { + if (item.type == "menu") { + dispatch({type: "COLLAPSE_MENU", key: item.key}); + } + handleDrawerToggle(); + }} + > + + + + + + + ))} + + + ); }; export default SidebarListSubItem; diff --git a/src/layouts/dashboardLayouts/sidebar/index.jsx b/src/layouts/dashboardLayouts/sidebar/index.jsx index dcf7fe2..2498dfd 100644 --- a/src/layouts/dashboardLayouts/sidebar/index.jsx +++ b/src/layouts/dashboardLayouts/sidebar/index.jsx @@ -1,46 +1,46 @@ -import { Box, Drawer } from "@mui/material"; +import {Box, Drawer} from "@mui/material"; import SidebarDrawer from "./SidebarDrawer"; const Sidebar = (props) => { - return ( - - - - - - - - - ); + return ( + + + + + + + + + ); }; export default Sidebar; diff --git a/src/lib/app/contexts/language.jsx b/src/lib/app/contexts/language.jsx index c8ac313..e3f41f4 100644 --- a/src/lib/app/contexts/language.jsx +++ b/src/lib/app/contexts/language.jsx @@ -1,99 +1,99 @@ -import { FA_DATATABLE_LOCALIZATION } from "&/locales/fa/datatable"; -import { useRouter } from "next/router"; -import { createContext, useEffect, useState } from "react"; +import {FA_DATATABLE_LOCALIZATION} from "&/locales/fa/datatable"; +import {useRouter} from "next/router"; +import {createContext, useEffect, useState} from "react"; import useUser from "../hooks/useUser"; export const LanguageContext = createContext(); -export const LanguageProvider = ({ children }) => { - const router = useRouter(); - const languageList = [ - { - key: "fa", - dir: "rtl", - name: "فارسی", - fontFamily: `IRANSans, sans-serif`, - tableLocalization: FA_DATATABLE_LOCALIZATION, - } - ]; - const { user, userChangedLanguage, changeLanguageState } = useUser(); - const [languageIsReady, setLanguageIsReady] = useState(false); - const [languageApp, setLanguageApp] = useState(); - const [directionApp, setDirectionApp] = useState( - process.env.NEXT_PUBLIC_DEFAULT_DIRECTION - ); - - useEffect(() => { - const lang = localStorage.getItem("_language"); - - if (!lang && !languageApp) { - setLanguageApp(process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE); - } else if (lang) { - setLanguageApp(lang); - } - }, []); - - useEffect(() => { - if (!languageApp) return; - - const lang = localStorage.getItem("_language"); - - if (!lang) { - localStorage.setItem("_language", languageApp); - } else { - if (languageApp != lang) { - localStorage.setItem("_language", languageApp); - } - } - }, [languageApp]); - - useEffect(() => { - if (!router.isReady) return; - if (user.user_language) { - if (user.user_language != languageApp) { - setLanguageApp(user.user_language); - return; - } - } - - if (languageApp != router.locale) { - router.replace( - { pathname: router.pathname, query: router.query }, - router.asPath, +export const LanguageProvider = ({children}) => { + const router = useRouter(); + const languageList = [ { - locale: languageApp, + key: "fa", + dir: "rtl", + name: "فارسی", + fontFamily: `IRANSans, sans-serif`, + tableLocalization: FA_DATATABLE_LOCALIZATION, } - ); - return; - } - for (const lang of languageList) { - if (languageApp != lang.key) continue; - setDirectionApp(lang.dir); - document.dir = lang.dir; - } + ]; + const {user, userChangedLanguage, changeLanguageState} = useUser(); + const [languageIsReady, setLanguageIsReady] = useState(false); + const [languageApp, setLanguageApp] = useState(); + const [directionApp, setDirectionApp] = useState( + process.env.NEXT_PUBLIC_DEFAULT_DIRECTION + ); - const timer = setTimeout(() => { - changeLanguageState(false); - setLanguageIsReady(true); - }, 1000); + useEffect(() => { + const lang = localStorage.getItem("_language"); - return () => { - clearTimeout(timer); - }; - }, [router.locale, router.isReady, userChangedLanguage, languageApp]); + if (!lang && !languageApp) { + setLanguageApp(process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE); + } else if (lang) { + setLanguageApp(lang); + } + }, []); - return ( - - {children} - - ); + useEffect(() => { + if (!languageApp) return; + + const lang = localStorage.getItem("_language"); + + if (!lang) { + localStorage.setItem("_language", languageApp); + } else { + if (languageApp != lang) { + localStorage.setItem("_language", languageApp); + } + } + }, [languageApp]); + + useEffect(() => { + if (!router.isReady) return; + if (user.user_language) { + if (user.user_language != languageApp) { + setLanguageApp(user.user_language); + return; + } + } + + if (languageApp != router.locale) { + router.replace( + {pathname: router.pathname, query: router.query}, + router.asPath, + { + locale: languageApp, + } + ); + return; + } + for (const lang of languageList) { + if (languageApp != lang.key) continue; + setDirectionApp(lang.dir); + document.dir = lang.dir; + } + + const timer = setTimeout(() => { + changeLanguageState(false); + setLanguageIsReady(true); + }, 1000); + + return () => { + clearTimeout(timer); + }; + }, [router.locale, router.isReady, userChangedLanguage, languageApp]); + + return ( + + {children} + + ); }; diff --git a/src/lib/app/contexts/loading.jsx b/src/lib/app/contexts/loading.jsx index 6e95a8c..f5b8a47 100644 --- a/src/lib/app/contexts/loading.jsx +++ b/src/lib/app/contexts/loading.jsx @@ -1,14 +1,14 @@ import LoadingHardPage from "@/core/components/LoadingHardPage"; -import { createContext, useState } from "react"; +import {createContext, useState} from "react"; export const LoadingContext = createContext(); -export const LoadingProvider = ({ children }) => { - const [loadingPage, setLoadingPage] = useState(false); - return ( - - - {children} - - ); +export const LoadingProvider = ({children}) => { + const [loadingPage, setLoadingPage] = useState(false); + return ( + + + {children} + + ); }; diff --git a/src/lib/app/contexts/user.jsx b/src/lib/app/contexts/user.jsx index 49d55af..10611b8 100644 --- a/src/lib/app/contexts/user.jsx +++ b/src/lib/app/contexts/user.jsx @@ -1,144 +1,132 @@ -import { - GET_USER_ROUTE, - SET_LANGUAGE -} from "@/core/data/apiRoutes"; +import {GET_USER_ROUTE} from "@/core/data/apiRoutes"; import axios from "axios"; -import { createContext, useCallback, useEffect, useReducer } from "react"; +import {createContext, useCallback, useEffect, useReducer} from "react"; +import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler"; const initialUser = { - isAuth: false, - userChangedLanguage: false, - token: null, - user: {}, + isAuth: false, + userChangedLanguage: false, + token: null, + user: {}, }; const reducer = (state, action) => { - switch (action.type) { - case "CLEAR_USER": - return { ...state, user: {} }; - case "CHANGE_USER": - return { ...state, user: action.user }; - case "CHANGE_USER_LANGUAGE": - return { - ...state, - user: { ...state.user, user_language: action.language }, - }; - case "CHANGE_AUTH_STATE": - return { ...state, isAuth: action.isAuth }; - case "CHANGE_LANGUAGE_STATE": - return { ...state, userChangedLanguage: action.userChangedLanguage }; - case "CLEAR_TOKEN": - localStorage.removeItem("_token"); - return { ...state, token: null }; - case "SET_TOKEN": - localStorage.setItem("_token", action.token); - return { ...state, token: action.token }; - default: - return state; - } + switch (action.type) { + case "CLEAR_USER": + return {...state, user: {}}; + case "CHANGE_USER": + return {...state, user: action.user}; + case "CHANGE_USER_LANGUAGE": + return { + ...state, + user: {...state.user, user_language: action.language}, + }; + case "CHANGE_AUTH_STATE": + return {...state, isAuth: action.isAuth}; + case "CHANGE_LANGUAGE_STATE": + return {...state, userChangedLanguage: action.userChangedLanguage}; + case "CLEAR_TOKEN": + localStorage.removeItem("_token"); + return {...state, token: null}; + case "SET_TOKEN": + localStorage.setItem("_token", action.token); + return {...state, token: action.token}; + default: + return state; + } }; export const UserContext = createContext(); -export const UserProvider = ({ children }) => { - const [state, dispatch] = useReducer(reducer, initialUser); +export const UserProvider = ({children}) => { + const [state, dispatch] = useReducer(reducer, initialUser); - const clearUser = useCallback(() => { - dispatch({ type: "CLEAR_USER" }); - }, []); + const clearUser = useCallback(() => { + dispatch({type: "CLEAR_USER"}); + }, []); - const changeUser = useCallback((user) => { - dispatch({ type: "CHANGE_USER", user }); - }, []); + const changeUser = useCallback((user) => { + dispatch({type: "CHANGE_USER", user}); + }, []); - const changeUserLanguage = useCallback( - (language) => { - dispatch({ type: "CHANGE_USER_LANGUAGE", language }); - axios - .post( - SET_LANGUAGE, - { language: language }, - { - headers: { - authorization: `Bearer ${state.token}`, - }, - } - ) - .then(() => { - getUser((data) => { + const changeUserLanguage = useCallback(/* use in multi language app */); + + const changeAuthState = useCallback((isAuth) => { + dispatch({type: "CHANGE_AUTH_STATE", isAuth}); + }, []); + + const changeLanguageState = useCallback((userChangedLanguage) => { + dispatch({type: "CHANGE_LANGUAGE_STATE", userChangedLanguage}); + }, []); + + const clearToken = useCallback(() => { + dispatch({type: "CLEAR_TOKEN"}); + }, []); + + const setToken = useCallback((token) => { + dispatch({type: "SET_TOKEN", token}); + }, []); + + const getUser = useCallback( + (callback = () => { + }) => { + axios + .get(GET_USER_ROUTE, { + headers: {authorization: `Bearer ${state.token}`}, + }) + .then(({data}) => { + if (typeof callback === "function") callback(data); + }) + .catch(error => { + if (error.response) { + errorResponse(error.response, clearToken, null, false) + } else if (error.request) { + errorRequest(null, false) + } else { + errorSetting(null, false) + } + }) + }, + [state.token] + ); + + useEffect(() => { + const localToken = localStorage.getItem("_token"); + if (localToken) dispatch({type: "SET_TOKEN", token: localToken}); + }, []); + + useEffect(() => { + if (!state.token) { + clearUser(); + changeAuthState(false); + changeLanguageState(false); + return; + } + getUser((data) => { changeUser(data); - }); + changeAuthState(true); + changeLanguageState(true); }); - }, - [state.token] - ); + }, [state.token]); - const changeAuthState = useCallback((isAuth) => { - dispatch({ type: "CHANGE_AUTH_STATE", isAuth }); - }, []); - - const changeLanguageState = useCallback((userChangedLanguage) => { - dispatch({ type: "CHANGE_LANGUAGE_STATE", userChangedLanguage }); - }, []); - - const clearToken = useCallback(() => { - dispatch({ type: "CLEAR_TOKEN" }); - }, []); - - const setToken = useCallback((token) => { - dispatch({ type: "SET_TOKEN", token }); - }, []); - - const getUser = useCallback( - (callback = () => {}) => { - axios - .get(GET_USER_ROUTE, { - headers: { authorization: `Bearer ${state.token}` }, - }) - .then(({ data }) => { - if (typeof callback === "function") callback(data); - }); - }, - [state.token] - ); - - useEffect(() => { - const localToken = localStorage.getItem("_token"); - if (localToken) dispatch({ type: "SET_TOKEN", token: localToken }); - }, []); - - useEffect(() => { - if (!state.token) { - clearUser(); - changeAuthState(false); - changeLanguageState(false); - return; - } - getUser((data) => { - changeUser(data); - changeAuthState(true); - changeLanguageState(true); - }); - }, [state.token]); - - return ( - - {children} - - ); + return ( + + {children} + + ); }; diff --git a/src/lib/app/hooks/useDirection.jsx b/src/lib/app/hooks/useDirection.jsx index e45cb24..b2e01fe 100644 --- a/src/lib/app/hooks/useDirection.jsx +++ b/src/lib/app/hooks/useDirection.jsx @@ -1,10 +1,10 @@ -import { useContext } from "react"; -import { LanguageContext } from "../contexts/language"; +import {useContext} from "react"; +import {LanguageContext} from "../contexts/language"; const useDirection = () => { - const { directionApp } = useContext(LanguageContext); + const {directionApp} = useContext(LanguageContext); - return { directionApp }; + return {directionApp}; }; export default useDirection; diff --git a/src/lib/app/hooks/useLanguage.jsx b/src/lib/app/hooks/useLanguage.jsx index 66e2ee0..d663835 100644 --- a/src/lib/app/hooks/useLanguage.jsx +++ b/src/lib/app/hooks/useLanguage.jsx @@ -1,28 +1,28 @@ -import { useContext } from "react"; -import { LanguageContext } from "../contexts/language"; +import {useContext} from "react"; +import {LanguageContext} from "../contexts/language"; import useUser from "./useUser"; const useLanguage = () => { - const { isAuth, changeUserLanguage } = useUser(); - const { - languageApp, - setLanguageApp, - languageIsReady, - setLanguageIsReady, - languageList, - } = useContext(LanguageContext); + const {isAuth, changeUserLanguage} = useUser(); + const { + languageApp, + setLanguageApp, + languageIsReady, + setLanguageIsReady, + languageList, + } = useContext(LanguageContext); - const changeLanguage = (lang) => { - if (lang == languageApp) return; + const changeLanguage = (lang) => { + if (lang == languageApp) return; - setLanguageIsReady(false); - setLanguageApp(lang); - if (isAuth) { - changeUserLanguage(lang); - } - }; + setLanguageIsReady(false); + setLanguageApp(lang); + if (isAuth) { + changeUserLanguage(lang); + } + }; - return { languageApp, changeLanguage, languageIsReady, languageList }; + return {languageApp, changeLanguage, languageIsReady, languageList}; }; export default useLanguage; diff --git a/src/lib/app/hooks/useLoading.jsx b/src/lib/app/hooks/useLoading.jsx index d74a87e..a691bd7 100644 --- a/src/lib/app/hooks/useLoading.jsx +++ b/src/lib/app/hooks/useLoading.jsx @@ -1,10 +1,10 @@ -import { useContext } from "react"; -import { LoadingContext } from "../contexts/loading"; +import {useContext} from "react"; +import {LoadingContext} from "../contexts/loading"; const useLoading = () => { - const { setLoadingPage } = useContext(LoadingContext); + const {setLoadingPage} = useContext(LoadingContext); - return { setLoadingPage }; + return {setLoadingPage}; }; export default useLoading; diff --git a/src/lib/app/hooks/useNetwork.jsx b/src/lib/app/hooks/useNetwork.jsx new file mode 100644 index 0000000..84e2950 --- /dev/null +++ b/src/lib/app/hooks/useNetwork.jsx @@ -0,0 +1,58 @@ +import {useEffect, useState} from "react"; + +function getNetworkConnection() { + return ( + navigator.connection || + navigator.mozConnection || + navigator.webkitConnection || + null + ); +} + +function getNetworkConnectionInfo() { + const connection = getNetworkConnection(); + if (!connection) { + return {}; + } + return { + rtt: connection.rtt, + type: connection.type, + saveData: connection.saveData, + downLink: connection.downLink, + downLinkMax: connection.downLinkMax, + effectiveType: connection.effectiveType, + }; +} + +function useNetwork() { + const [state, setState] = useState(() => { + return { + online: navigator.onLine, + }; + }); + useEffect(() => { + const handleOnline = () => { + setState((prevState) => ({ + ...prevState, + online: true, + })); + }; + const handleOffline = () => { + setState((prevState) => ({ + ...prevState, + online: false, + })); + }; + + window.addEventListener("online", handleOnline); + window.addEventListener("offline", handleOffline); + return () => { + window.removeEventListener("online", handleOnline); + window.removeEventListener("offline", handleOffline); + }; + }, []); + + return state; +} + +export default useNetwork; \ No newline at end of file diff --git a/src/lib/app/hooks/useNotification.jsx b/src/lib/app/hooks/useNotification.jsx new file mode 100644 index 0000000..e32f829 --- /dev/null +++ b/src/lib/app/hooks/useNotification.jsx @@ -0,0 +1,23 @@ +import useSWR from 'swr' +import {GET_SIDEBAR_NOTIFICATION} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; + +const useNotification = () => { + const requestServer = useRequest({auth: true, notification: false}) + + //swr config + const fetcher = (...args) => { + return requestServer(args, 'get').then((response) => { + return response.data.data; + }).catch(() => { + }) + }; + + const {data, mutate} = useSWR(GET_SIDEBAR_NOTIFICATION, fetcher) + const notification_count = data + //swr config + + // render data + return {notification_count, update_notification: mutate} +} +export default useNotification \ No newline at end of file diff --git a/src/lib/app/hooks/useRequest.jsx b/src/lib/app/hooks/useRequest.jsx new file mode 100644 index 0000000..d361e08 --- /dev/null +++ b/src/lib/app/hooks/useRequest.jsx @@ -0,0 +1,66 @@ +import axios from "axios"; +import {successRequest} from "@/core/utils/succesHandler"; +import PendingNotification from "@/core/components/notifications/PendingNotification"; +import {useTranslations} from "next-intl"; +import useUser from "@/lib/app/hooks/useUser"; +import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler"; +import useNetwork from "@/lib/app/hooks/useNetwork"; + +const defaultOptions = { + auth: false, data: {}, requestOptions: { + headers: {} + }, notification: true, pending: true, success: { + notification: { + show: true, + }, + }, failed: { + notification: { + show: true, + }, + }, +} +const useRequest = (initOptions) => { + const network = useNetwork() + const t = useTranslations() + const {token, clearToken} = useUser() + let _options = {...defaultOptions, ...initOptions} + + function requestServer(url = '', method = 'get', options) { + _options = {..._options, ...options} + if (_options.auth) _options = { + ..._options, requestOptions: { + ..._options.requestOptions, + headers: {..._options.requestOptions.headers, authorization: `Bearer ${token}`} + } + } + + return new Promise((resolve, reject) => { + if (!network.online) { + reject() + return + } + if (_options.notification && _options.failed.notification.show && _options.pending) PendingNotification(t) + axios({ + url: url, method: method, data: _options.data, ..._options.requestOptions + }) + .then(response => { + successRequest(response, t, _options) + resolve(response) + }) + .catch(error => { + if (error.response) { + errorResponse(error.response, clearToken, t, _options.notification && _options.failed.notification.show) + } else if (error.request) { + errorRequest(t, _options.notification && _options.failed.notification.show) + } else { + errorSetting(t, _options.notification && _options.failed.notification.show) + } + reject(error) + }) + }); + } + + return requestServer +} + +export default useRequest \ No newline at end of file diff --git a/src/lib/app/hooks/useUser.jsx b/src/lib/app/hooks/useUser.jsx index baa0aaa..b0bbc1a 100644 --- a/src/lib/app/hooks/useUser.jsx +++ b/src/lib/app/hooks/useUser.jsx @@ -1,36 +1,34 @@ -import { useContext } from "react"; -import { UserContext } from "../contexts/user"; +import {useContext} from "react"; +import {UserContext} from "../contexts/user"; const useUser = () => { - const { - isAuth, - userChangedLanguage, - token, - user, - getUser, - clearUser, - changeUser, - changeUserLanguage, - changeAuthState, - changeLanguageState, - clearToken, - setToken, - } = useContext(UserContext); + const { + isAuth, + userChangedLanguage, + token, + user, + getUser, + clearUser, + changeUser, + changeAuthState, + changeLanguageState, + clearToken, + setToken, + } = useContext(UserContext); - return { - isAuth, - userChangedLanguage, - token, - user, - getUser, - clearUser, - changeUser, - changeUserLanguage, - changeAuthState, - changeLanguageState, - clearToken, - setToken, - }; + return { + isAuth, + userChangedLanguage, + token, + user, + getUser, + clearUser, + changeUser, + changeAuthState, + changeLanguageState, + clearToken, + setToken, + }; }; export default useUser; diff --git a/src/middlewares/RolePermission.jsx b/src/middlewares/RolePermission.jsx new file mode 100644 index 0000000..67fc3f1 --- /dev/null +++ b/src/middlewares/RolePermission.jsx @@ -0,0 +1,43 @@ +import {NextLinkComposed} from "@/core/components/LinkRouting"; +import Message from "@/core/components/Messages"; +import useUser from "@/lib/app/hooks/useUser"; +import {Button, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; + +const RolePermissionMiddleware = ({children, requiredPermissions}) => { + const {user} = useUser(); + const t = useTranslations(); + + const hasPermission = requiredPermissions.some((permission) => + user?.permissions?.includes(permission) + ); + + if (!hasPermission) { + return ( + + {t("Permission.typography_you_dont_have_access")} + + } + actions={ + <> + + + } + /> + ); + } + + return <>{children}; +}; + +export default RolePermissionMiddleware; diff --git a/src/middlewares/WithAuth.jsx b/src/middlewares/WithAuth.jsx index d158bf3..b20d8b3 100644 --- a/src/middlewares/WithAuth.jsx +++ b/src/middlewares/WithAuth.jsx @@ -1,42 +1,42 @@ -import { NextLinkComposed } from "@/core/components/LinkRouting"; +import {NextLinkComposed} from "@/core/components/LinkRouting"; import Message from "@/core/components/Messages"; import useUser from "@/lib/app/hooks/useUser"; -import { Button, Typography } from "@mui/material"; -import { useTranslations } from "next-intl"; -import { useRouter } from "next/router"; +import {Button, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useRouter} from "next/router"; -const WithAuthMiddleware = ({ children }) => { - const { isAuth } = useUser(); - const t = useTranslations(); - const router = useRouter(); +const WithAuthMiddleware = ({children}) => { + const {isAuth} = useUser(); + const t = useTranslations(); + const router = useRouter(); - if (!isAuth) - return ( - - {t( - "typography_your_access_to_this_page_has_expired_Please_login_again" - )} - - } - actions={ - <> - - - } - /> - ); - return <>{children}; + if (!isAuth) + return ( + + {t( + "Authorization.typography_your_access_to_this_page_has_expired_Please_login_again" + )} + + } + actions={ + <> + + + } + /> + ); + return <>{children}; }; export default WithAuthMiddleware; diff --git a/src/middlewares/WithoutAuth.jsx b/src/middlewares/WithoutAuth.jsx index 5fb4f93..594ffc5 100644 --- a/src/middlewares/WithoutAuth.jsx +++ b/src/middlewares/WithoutAuth.jsx @@ -1,56 +1,56 @@ import Message from "@/core/components/Messages"; import useUser from "@/lib/app/hooks/useUser"; -import { Stack, Typography } from "@mui/material"; -import { useTranslations } from "next-intl"; -import { useSearchParams } from "next/navigation"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; +import {Stack, Typography} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useSearchParams} from "next/navigation"; +import {useRouter} from "next/router"; +import {useEffect} from "react"; -const WithoutAuthMiddleware = ({ children }) => { - const { isAuth } = useUser(); - const t = useTranslations(); - const router = useRouter(); +const WithoutAuthMiddleware = ({children}) => { + const {isAuth} = useUser(); + const t = useTranslations(); + const router = useRouter(); - // gettin url query - const searchParams = useSearchParams(); - const backUrlDecodedPath = searchParams.get("back_url"); + // gettin url query + const searchParams = useSearchParams(); + const backUrlDecodedPath = searchParams.get("back_url"); - useEffect(() => { - if (!isAuth) return; - const timer = setTimeout(() => { - router.replace( - backUrlDecodedPath - ? decodeURIComponent(backUrlDecodedPath) - : "/dashboard" - ); - }, 2000); + useEffect(() => { + if (!isAuth) return; + const timer = setTimeout(() => { + router.replace( + backUrlDecodedPath + ? decodeURIComponent(backUrlDecodedPath) + : "/dashboard" + ); + }, 2000); - return () => { - clearTimeout(timer); - }; - }, [isAuth]); + return () => { + clearTimeout(timer); + }; + }, [isAuth]); - if (isAuth) - return ( - - - {t( - "typography_your_login_is_valid_and_you_do_not_need_to_login_again" - )} - - - {t("typography_redirect_to")}{" "} - {backUrlDecodedPath - ? t("typography_routing_previuos_page") - : t("typography_routing_dashbaord_page")} - - - } - /> - ); - return <>{children}; + if (isAuth) + return ( + + + {t( + "Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again" + )} + + + {t("Authorization.typography_redirect_to")}{" "} + {backUrlDecodedPath + ? t("Authorization.typography_routing_previuos_page") + : t("Authorization.typography_routing_dashbaord_page")} + + + } + /> + ); + return <>{children}; }; export default WithoutAuthMiddleware; diff --git a/src/pages/403.jsx b/src/pages/403.jsx new file mode 100644 index 0000000..15ba915 --- /dev/null +++ b/src/pages/403.jsx @@ -0,0 +1,24 @@ +import {useEffect, useState} from "react"; +import {useRouter} from "next/router"; +import {NextIntlProvider} from "next-intl"; +import UnAuthorizedComponent from "@/components/errors/403"; + +export default function Custom404() { + const router = useRouter() + const [messages, setMessages] = useState(null) + useEffect(() => { + const fetch = async () => { + const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default + setMessages(tempMessages) + } + fetch() + }, []); + + if (!messages) return + + return ( + + + + ); +} diff --git a/src/pages/404.jsx b/src/pages/404.jsx new file mode 100644 index 0000000..26de038 --- /dev/null +++ b/src/pages/404.jsx @@ -0,0 +1,25 @@ +import {useEffect, useState} from "react"; +import {useRouter} from "next/router"; +import {NextIntlProvider} from "next-intl"; +import NotFoundComponent from "@/components/errors/404"; + +export default function Custom404() { + const router = useRouter() + const [messages, setMessages] = useState(null) + useEffect(() => { + + const fetch = async () => { + const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default + setMessages(tempMessages) + } + fetch() + }, []); + + if (!messages) return + + return ( + + + + ); +} diff --git a/src/pages/500.jsx b/src/pages/500.jsx new file mode 100644 index 0000000..4b85bc2 --- /dev/null +++ b/src/pages/500.jsx @@ -0,0 +1,24 @@ +import {useEffect, useState} from "react"; +import {useRouter} from "next/router"; +import {NextIntlProvider} from "next-intl"; +import ServerErrorComponent from "@/components/errors/500"; + +export default function Custom500() { + const router = useRouter() + const [messages, setMessages] = useState(null) + useEffect(() => { + const fetch = async () => { + const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default + setMessages(tempMessages) + } + fetch() + }, []); + + if (!messages) return + + return ( + + + + ); +} diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index be5d828..29ec464 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -1,30 +1,33 @@ import "&/fontiran.scss"; import AppLayout from "@/layouts/AppLayout"; import MuiLayout from "@/layouts/MuiLayout"; -import { LanguageProvider } from "@/lib/app/contexts/language"; -import { LoadingProvider } from "@/lib/app/contexts/loading"; -import { UserProvider } from "@/lib/app/contexts/user"; +import {LanguageProvider} from "@/lib/app/contexts/language"; +import {LoadingProvider} from "@/lib/app/contexts/loading"; +import {UserProvider} from "@/lib/app/contexts/user"; import "moment/locale/fa"; -import { NextIntlProvider } from "next-intl"; +import {NextIntlProvider} from "next-intl"; +import TitlePage from "@/core/components/TitlePage"; -const App = ({ Component, pageProps }) => { - return ( - <> - - - - - - - - - - - - - - - ); +const App = ({Component, pageProps}) => { + + return ( + <> + + + + + {pageProps.messages ? : ''} + + + + + + + + + + + ); }; export default App; diff --git a/src/pages/_document.jsx b/src/pages/_document.jsx index e763884..474e29b 100644 --- a/src/pages/_document.jsx +++ b/src/pages/_document.jsx @@ -1,67 +1,61 @@ -import { - createEmotionCacheLtr -} from "@/core/utils/createEmotionCache"; +import {createEmotionCacheRtl} from "@/core/utils/createEmotionCache"; import theme from "@/core/utils/theme"; import createEmotionServer from "@emotion/server/create-instance"; -import Document, { Head, Html, Main, NextScript } from "next/document"; +import Document, {Head, Html, Main, NextScript} from "next/document"; export default function MyDocument(props) { - const { emotionStyleTags } = props; + const {emotionStyleTags} = props; - return ( - - - - - - - - {emotionStyleTags} - - -
- - - - ); + return ( + + + + + + + {emotionStyleTags} + + +
+ + + + ); } MyDocument.getInitialProps = async (ctx) => { - const originalRenderPage = ctx.renderPage; - let cache; - switch (ctx.locale) { - case "fa": - cache = createEmotionCacheLtr(); - break; - } + const originalRenderPage = ctx.renderPage; + let cache; + switch (ctx.locale) { + case "fa": + cache = createEmotionCacheRtl(); + break; + } - const { extractCriticalToChunks } = createEmotionServer(cache); + const {extractCriticalToChunks} = createEmotionServer(cache); - ctx.renderPage = () => - originalRenderPage({ - enhanceApp: (App) => - function EnhanceApp(props) { - return ; - }, - }); + ctx.renderPage = () => + originalRenderPage({ + enhanceApp: (App) => + function EnhanceApp(props) { + return ; + }, + }); - const initialProps = await Document.getInitialProps(ctx); + const initialProps = await Document.getInitialProps(ctx); - const emotionStyles = extractCriticalToChunks(initialProps.html); - const emotionStyleTags = emotionStyles.styles.map((style) => ( -