Merge branch 'release/V1.21.6'
This commit is contained in:
485
.editorconfig
Normal file
485
.editorconfig
Normal file
@@ -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
|
||||
5
.eslintrc.json
Normal file
5
.eslintrc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"next/core-web-vitals"
|
||||
]
|
||||
}
|
||||
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
.next
|
||||
.env*
|
||||
.env
|
||||
.idea
|
||||
package-lock.json
|
||||
ecosystem.config.js
|
||||
118
.gitlab-ci.yml
Normal file
118
.gitlab-ci.yml
Normal file
@@ -0,0 +1,118 @@
|
||||
image: node:latest
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- test:build
|
||||
- deploy
|
||||
|
||||
merge:build:
|
||||
stage: build
|
||||
script:
|
||||
- npm install
|
||||
- cp example.env.local .env.local
|
||||
- cp example.env.local .env.test
|
||||
only:
|
||||
- merge_requests
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
merge:test:jest:
|
||||
stage: test
|
||||
script:
|
||||
- npm run test
|
||||
only:
|
||||
- merge_requests
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
merge:test:lint:
|
||||
stage: test
|
||||
script:
|
||||
- npm run lint
|
||||
only:
|
||||
- merge_requests
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
#merge:test:build:
|
||||
# stage: test:build
|
||||
# script:
|
||||
# - npm run build
|
||||
# only:
|
||||
# - merge_requests
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - node_modules
|
||||
# - .env.local
|
||||
# - .env.test
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- npm install
|
||||
- cp example.env.local .env.local
|
||||
- cp example.env.local .env.test
|
||||
only:
|
||||
- develop
|
||||
- main
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
test:jest:
|
||||
stage: test
|
||||
script:
|
||||
- npm run test
|
||||
only:
|
||||
- develop
|
||||
- main
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
test:lint:
|
||||
stage: test
|
||||
script:
|
||||
- npm run lint
|
||||
only:
|
||||
- develop
|
||||
- main
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
- .env.local
|
||||
- .env.test
|
||||
|
||||
#test:build:
|
||||
# stage: test:build
|
||||
# script:
|
||||
# - npm run build
|
||||
# only:
|
||||
# - develop
|
||||
# - main
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - node_modules
|
||||
# - .env.local
|
||||
# - .env.test
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Run deploy project"
|
||||
only:
|
||||
- main
|
||||
16
cypress.config.js
Normal file
16
cypress.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const { defineConfig } = require("cypress");
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
|
||||
component: {
|
||||
devServer: {
|
||||
framework: "next",
|
||||
bundler: "webpack",
|
||||
},
|
||||
},
|
||||
});
|
||||
25
cypress/support/commands.js
Normal file
25
cypress/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
14
cypress/support/component-index.html
Normal file
14
cypress/support/component-index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Components App</title>
|
||||
<!-- Used by Next.js to inject CSS. -->
|
||||
<div id="__next_css__DO_NOT_USE__"></div>
|
||||
</head>
|
||||
<body>
|
||||
<div data-cy-root></div>
|
||||
</body>
|
||||
</html>
|
||||
27
cypress/support/component.js
Normal file
27
cypress/support/component.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// ***********************************************************
|
||||
// This example support/component.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
import { mount } from 'cypress/react18'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
// Example use:
|
||||
// cy.mount(<MyComponent />)
|
||||
20
cypress/support/e2e.js
Normal file
20
cypress/support/e2e.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
18
ecosystem.config.js.example
Normal file
18
ecosystem.config.js.example
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: "crm_app",
|
||||
script: 'node_modules/next/dist/bin/next', // cluster mode run with node only, not npm
|
||||
args: 'start -p 3003',
|
||||
exec_mode: "cluster", // default fork
|
||||
instances: "10",
|
||||
kill_timeout: 4000,
|
||||
wait_ready: true,
|
||||
autorestart: true,
|
||||
watch: false,
|
||||
max_memory_restart: "1G",
|
||||
log_date_format: "YYYY-MM-DD HH:mm Z",
|
||||
env_prod: {
|
||||
APP_ENV: 'prod' // APP_ENV=prod
|
||||
}
|
||||
}],
|
||||
};
|
||||
17
example.env.local
Normal file
17
example.env.local
Normal file
@@ -0,0 +1,17 @@
|
||||
NEXT_PUBLIC_API_NAME = "CRM Dashboard"
|
||||
NEXT_PUBLIC_API_VERSION = "1.21.6"
|
||||
NEXT_PUBLIC_DEFAULT_LANGUAGE = "fa"
|
||||
NEXT_PUBLIC_DEFAULT_DIRECTION = "rtl"
|
||||
|
||||
NEXT_PUBLIC_PRIMARY_MAIN = "#1b4332"
|
||||
NEXT_PUBLIC_SECONDARY_MAIN = "#800e13"
|
||||
|
||||
NEXT_PUBLIC_BASE_URL = "https://crm.witel.ir"
|
||||
NEXT_PUBLIC_SERVER_SOCKET_URL = "wss://crmws.witel.ir"
|
||||
NEXT_PUBLIC_POWERED_BY_URL = "https://witel.ir"
|
||||
|
||||
#["NEXT_PUBLIC_HAS_WIDGET" , "NEXT_PUBLIC_HAS_NOTIFICATION"]
|
||||
NEXT_PUBLIC_HAS_VALUE=["NEXT_PUBLIC_HAS_WIDGET"]
|
||||
|
||||
NODE_ENV = "development"
|
||||
|
||||
17
jest.config.mjs
Normal file
17
jest.config.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
import nextJest from 'next/jest.js'
|
||||
|
||||
const createJestConfig = nextJest({
|
||||
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
|
||||
dir: './',
|
||||
})
|
||||
|
||||
// Add any custom config to be passed to Jest
|
||||
/** @type {import('jest').Config} */
|
||||
const config = {
|
||||
// Add more setup options before each test is run
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
||||
testEnvironment: 'jest-environment-jsdom',
|
||||
}
|
||||
|
||||
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
|
||||
export default createJestConfig(config)
|
||||
23
jest.setup.js
Normal file
23
jest.setup.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import '@testing-library/jest-dom'
|
||||
import {server} from "./mocks/server";
|
||||
import mockRouter from 'next-router-mock'
|
||||
|
||||
jest.mock('next/router', () => jest.requireActual('next-router-mock'))
|
||||
|
||||
beforeAll(() => {
|
||||
server.listen()
|
||||
})
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
mockRouter.query = {}
|
||||
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
server.resetHandlers()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
server.close()
|
||||
})
|
||||
|
||||
12
jsconfig.json
Normal file
12
jsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"&/*": [
|
||||
"./public/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
13
mocks/AppWithProvider.jsx
Normal file
13
mocks/AppWithProvider.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import App from "@/pages/_app";
|
||||
import fa from "&/locales/fa/app.json"
|
||||
|
||||
const translations = {fa};
|
||||
const MockAppWithProviders = ({children, locale, title, isBot}) => {
|
||||
const pageProps = {
|
||||
title: title || '', isBot: isBot || true, locale: locale || 'fa', messages: translations[locale || 'fa']
|
||||
}
|
||||
|
||||
return (<App Component={() => (<>{children}</>)} pageProps={pageProps}/>)
|
||||
}
|
||||
|
||||
export default MockAppWithProviders
|
||||
15
mocks/handler.js
Normal file
15
mocks/handler.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { userHandler } from "./handlers/user";
|
||||
import { permissionsHandler } from "./handlers/permissions";
|
||||
import { rolesHandler } from "./handlers/roles";
|
||||
import { provincesHandler } from "./handlers/provinces";
|
||||
import { expertsHandler } from "./handlers/experts";
|
||||
import { categoriesHandler } from "./handlers/categories";
|
||||
|
||||
export const handler = [
|
||||
...userHandler,
|
||||
...permissionsHandler,
|
||||
...rolesHandler,
|
||||
...provincesHandler,
|
||||
...expertsHandler,
|
||||
...categoriesHandler,
|
||||
];
|
||||
25
mocks/handlers/categories.js
Normal file
25
mocks/handlers/categories.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { rest } from "msw";
|
||||
import { GET_CATEGORY } from "@/core/data/apiRoutes";
|
||||
|
||||
export const categoriesHandler = [
|
||||
rest.get(GET_CATEGORY, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json({
|
||||
data: [
|
||||
{
|
||||
category_id: 1,
|
||||
category_name: "اطلاعات راه",
|
||||
subcategory_id: 1,
|
||||
subcategory_name: "اطلاعات باز و بسته",
|
||||
},
|
||||
{
|
||||
category_id: 3,
|
||||
category_name: "سایر",
|
||||
subcategory_id: 2,
|
||||
subcategory_name: "مزاحم",
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}),
|
||||
];
|
||||
20
mocks/handlers/experts.js
Normal file
20
mocks/handlers/experts.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import {rest} from "msw";
|
||||
import {ADD_EXPERT, DELETE_EXPERT, UPDATE_EXPERT} from "@/core/data/apiRoutes";
|
||||
|
||||
export const expertsHandler = [
|
||||
rest.post(ADD_EXPERT, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
);
|
||||
}),
|
||||
rest.delete(`${DELETE_EXPERT}/:id`, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
);
|
||||
}),
|
||||
rest.post(`${UPDATE_EXPERT}/:id`, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
);
|
||||
}),
|
||||
]
|
||||
23
mocks/handlers/permissions.js
Normal file
23
mocks/handlers/permissions.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import {rest} from "msw";
|
||||
import {GET_PERMISSIONS_LIST} from "@/core/data/apiRoutes";
|
||||
|
||||
export const permissionsHandler = [
|
||||
rest.get(GET_PERMISSIONS_LIST, (req, res, ctx) => {
|
||||
return res(ctx.json(
|
||||
{
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: "manage_passenger_office_navgan",
|
||||
name_fa: "مدیریت کارتابل رییس اداره مسافری استان"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "manage_province_working_group_navgan",
|
||||
name_fa: "مدیریت کارتابل کارگروه استانی"
|
||||
}
|
||||
]
|
||||
}
|
||||
))
|
||||
})
|
||||
]
|
||||
19
mocks/handlers/provinces.js
Normal file
19
mocks/handlers/provinces.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import {rest} from "msw";
|
||||
import {GET_PROVINCE_LIST} from "@/core/data/apiRoutes";
|
||||
|
||||
export const provincesHandler = [
|
||||
rest.get(GET_PROVINCE_LIST, (req, res, ctx) => {
|
||||
return res(ctx.json({
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: "آذربایجان شرقی"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "اردبیل"
|
||||
}
|
||||
]
|
||||
}))
|
||||
}),
|
||||
]
|
||||
70
mocks/handlers/roles.js
Normal file
70
mocks/handlers/roles.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import {rest} from "msw";
|
||||
import {GET_ROLE_LIST, GET_ROLES} from "@/core/data/apiRoutes";
|
||||
|
||||
export const rolesHandler = [
|
||||
rest.get(GET_ROLES, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json(
|
||||
{
|
||||
data: [
|
||||
{
|
||||
created_at: "2023-10-01T07:20:07.000000Z",
|
||||
guard_name: "api",
|
||||
id: 1,
|
||||
name: "admin",
|
||||
name_fa: "ادمین",
|
||||
permissions: [
|
||||
{
|
||||
id: 1,
|
||||
name: "manage_users",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "manage_roles",
|
||||
},
|
||||
],
|
||||
updated_at: "2023-10-10T07:38:12.000000Z"
|
||||
},
|
||||
{
|
||||
created_at: "2023-10-01T07:20:07.000000Z",
|
||||
guard_name: "api",
|
||||
id: 2,
|
||||
name: "manager",
|
||||
name_fa: "مدیر",
|
||||
permissions: [
|
||||
{
|
||||
id: 1,
|
||||
name: "manage_users",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "manage_roles",
|
||||
},
|
||||
],
|
||||
updated_at: "2023-10-10T07:38:12.000000Z"
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
totalRowCount: 2
|
||||
}
|
||||
}
|
||||
),
|
||||
);
|
||||
}),
|
||||
rest.get(GET_ROLE_LIST, (req, res, ctx) => {
|
||||
return res(ctx.json({
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: "admin",
|
||||
name_fa: "ادمین"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "manager",
|
||||
name_fa: "مدیر"
|
||||
}
|
||||
]
|
||||
}))
|
||||
}),
|
||||
]
|
||||
29
mocks/handlers/user.js
Normal file
29
mocks/handlers/user.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import {rest} from "msw";
|
||||
import {GET_SIDEBAR_NOTIFICATION, GET_USER, SET_USER_PASSWORD} from "@/core/data/apiRoutes";
|
||||
|
||||
export const userHandler = [
|
||||
rest.get(GET_USER, (req, res, ctx) => {
|
||||
return res(ctx.json({
|
||||
data:{
|
||||
id: 10,
|
||||
full_name: "Witel Company",
|
||||
position: "Software Engineer",
|
||||
permissions:[
|
||||
"manage_users",
|
||||
"manage_roles",
|
||||
"manage_boss"
|
||||
],
|
||||
}
|
||||
}))
|
||||
}),
|
||||
rest.get(GET_SIDEBAR_NOTIFICATION, (req, res, ctx) => {
|
||||
return res(ctx.json({
|
||||
data: []
|
||||
}))
|
||||
}),
|
||||
rest.post(SET_USER_PASSWORD, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
);
|
||||
}),
|
||||
]
|
||||
4
mocks/server.js
Normal file
4
mocks/server.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import {setupServer} from "msw/node";
|
||||
import {handler} from "./handler";
|
||||
|
||||
export const server = setupServer(...handler)
|
||||
12
next.config.js
Normal file
12
next.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
i18n: {
|
||||
defaultLocale: 'fa',
|
||||
locales: ['fa'],
|
||||
localeDetection: false,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
70
package.json
Normal file
70
package.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "dashboard",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"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 crm.service",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watchAll",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/server": "^11.10.0",
|
||||
"@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",
|
||||
"dotenv": "^16.3.1",
|
||||
"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",
|
||||
"nextjs-progressbar": "^0.0.16",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-toastify": "^9.1.3",
|
||||
"sass": "^1.62.0",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"stylis": "^4.1.3",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
"swr": "^2.1.5",
|
||||
"yup": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"cypress": "^13.2.0",
|
||||
"eslint-config-next": "^13.3.0",
|
||||
"eslint-plugin-jest-dom": "^5.1.0",
|
||||
"eslint-plugin-testing-library": "^6.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"msw": "^1.3.1",
|
||||
"next-router-mock": "^0.9.10",
|
||||
"run-script-os": "^1.1.6"
|
||||
}
|
||||
}
|
||||
169
public/fontiran.css
Normal file
169
public/fontiran.css
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
*
|
||||
* Name: IRAN Sans-Serif Font
|
||||
* Version: 5.0
|
||||
* Author: Moslem Ebrahimi (moslemebrahimi.com)
|
||||
* Created on: Dec 25, 2012
|
||||
* Updated on: Sep 01, 2017
|
||||
* Website: http://fontiran.com
|
||||
* Copyright: Commercial/Proprietary Software
|
||||
--------------------------------------------------------------------------------------
|
||||
فونت های ایران سن سریف یک نرم افزار مالکیتی محسوب می شود. جهت آگاهی از قوانین استفاده از این فونت ها لطفا به وب سایت (فونت ایران دات کام) مراجعه نمایید
|
||||
--------------------------------------------------------------------------------------
|
||||
IRAN Sans-serif fonts are considered a proprietary software. To gain information about the laws regarding the use of these fonts, please visit www.fontiran.com
|
||||
--------------------------------------------------------------------------------------
|
||||
This set of fonts are used in this project under the license: (.....)
|
||||
--------------------------------------------------------------------------------------
|
||||
*
|
||||
**/
|
||||
@font-face {
|
||||
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: 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: 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: 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: 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: 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: 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: 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');
|
||||
}
|
||||
BIN
public/fonts/eot/IRANSansWeb(FaNum).eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum).eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Black.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Black.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Light.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Light.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Black.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Black.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Bold.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Light.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Light.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Medium.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Medium.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_UltraLight.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_UltraLight.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/Parastoo-Bold.eot
Normal file
BIN
public/fonts/eot/Parastoo-Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/Parastoo.eot
Normal file
BIN
public/fonts/eot/Parastoo.eot
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum).ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum).ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Black.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Black.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Bold.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Light.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Light.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Medium.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Medium.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_UltraLight.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_UltraLight.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/Parastoo-Bold.ttf
Normal file
BIN
public/fonts/ttf/Parastoo-Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/Parastoo.ttf
Normal file
BIN
public/fonts/ttf/Parastoo.ttf
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum).woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum).woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Black.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Black.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Light.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Light.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Black.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Black.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Bold.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Light.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Light.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Medium.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Medium.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_UltraLight.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_UltraLight.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/Parastoo-Bold.woff
Normal file
BIN
public/fonts/woff/Parastoo-Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/Parastoo.woff
Normal file
BIN
public/fonts/woff/Parastoo.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum).woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum).woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Black.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Black.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Bold.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Light.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Light.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Medium.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Medium.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_UltraLight.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_UltraLight.woff2
Normal file
Binary file not shown.
BIN
public/icons/favicon.png
Normal file
BIN
public/icons/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
272
public/locales/fa/app.json
Normal file
272
public/locales/fa/app.json
Normal file
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"app_name": "سامانه CRM",
|
||||
"app_short_name": "سامانه CRM",
|
||||
"dashboard": "داشبورد",
|
||||
"powered_by_witel": "توسعه یافته توسط وایتل",
|
||||
"first_page": "خوش آمدید",
|
||||
"login": "ورود",
|
||||
"login_expert": "ورود کارشناس",
|
||||
"expert": "کارشناس",
|
||||
"last_updated_at": "اخرین بروز رسانی",
|
||||
"filter_mode": "حالت فیلتر",
|
||||
"date_picker_label": "فیلتر بر اساس تاریخ",
|
||||
"lessThan": "کوچکتر از",
|
||||
"greaterThan": "بزرگتر از",
|
||||
"between": "میان",
|
||||
"online_message": "شما به اینترنت وصل هستید",
|
||||
"offline_message": "اتصال شما به اینترنت قطع شده است",
|
||||
"socket_is_connect_message": "شما به سوکت وصل هستید",
|
||||
"socket_is_not_connect_message": "اتصال شما به سوکت قطع شده است",
|
||||
"header": {
|
||||
"open_profile": "پروفایل",
|
||||
"edit_profile": " پروفایل",
|
||||
"change_password": "تغییر رمز عبور",
|
||||
"logout": "خروج"
|
||||
},
|
||||
"Titles": {
|
||||
"title_login_page": "صفحه ورود",
|
||||
"title_login_expert_page": "ورود کارشناس",
|
||||
"title_custom_404": "صفحه یافت نشد",
|
||||
"title_custom_403": "عدم دسترسی",
|
||||
"title_custom_500": "خطای سرور"
|
||||
},
|
||||
"sidebar": {
|
||||
"dashboard": "داشبورد",
|
||||
"change-password": "تغییر رمز عبور",
|
||||
"edit-profile": "ویرایش پروفایل",
|
||||
"role-management": "مدیریت نقش ها",
|
||||
"admin": "مدیریت",
|
||||
"expert-management": "مدیریت کارشناسان"
|
||||
},
|
||||
"secondary": {
|
||||
},
|
||||
"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_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": "نام کاربری خود را وارد کنید",
|
||||
"text_field_password": "رمز عبور",
|
||||
"text_field_enter_your_password": "رمز عبور خود را وارد کنید",
|
||||
"button_submit": "ورود",
|
||||
"link_routing_back_to": "بازگشت به",
|
||||
"link_routing_previuos_page": "صفحه قبل",
|
||||
"link_routing_main_page": "صفحه اصلی",
|
||||
"username_error_message_required": "وارد کردن نام کاربری الزامیست",
|
||||
"password_error_message_required": "وارد کردن رمز عبور الزامیست"
|
||||
},
|
||||
"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": "داشبورد",
|
||||
"change_password": "تغییر رمز عبور",
|
||||
"edit_profile": "ویرایش پروفایل",
|
||||
"role_management_page": "مدیریت نقش ها",
|
||||
"expert_management": "مدیریت کارشناسان"
|
||||
},
|
||||
"MuiDatePicker": {
|
||||
"date_picker_birthday": "تاریخ"
|
||||
},
|
||||
"ChangePassword": {
|
||||
"typography_change_password": "تغییر رمز عبور",
|
||||
"label_current_password": "رمز عبور فعلی",
|
||||
"label_new_password": "رمز عبور جدید",
|
||||
"label_confirm_password": "تکرار رمز عبور جدید",
|
||||
"error_message_current_password_required": "وارد کردن رمز عبور فعلی الزامیست!",
|
||||
"error_message_new_password_required": "وارد کردن رمز عبور جدید الزامیست!",
|
||||
"error_message_confirm_password_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": "در حال انجام..."
|
||||
},
|
||||
"UploadSystem": {
|
||||
"upload_file": "فایل خود را بارگذاری کنید",
|
||||
"optional": " (اختیاری)",
|
||||
"upload_file_unit": "حداکثر 2Mb",
|
||||
"upload_file_format": "فرمت قابل قبول : png,jpg,pdf",
|
||||
"delete": "پاک کردن",
|
||||
"uploadfile_error": "حجم فایل بیشتر از 2 مگابایت می باشد"
|
||||
},
|
||||
"RoleManagement": {
|
||||
"id": "کد یکتا",
|
||||
"name_fa": "نام فارسی ",
|
||||
"name": "نام انگلیسی",
|
||||
"created_at": "تاریخ درخواست",
|
||||
"updated_at": "تاریخ بروزرسانی"
|
||||
},
|
||||
"AddDialog": {
|
||||
"add": "افزودن",
|
||||
"name_en": "نام انگلیسی",
|
||||
"name_en_error": "وارد کردن نام انگلیسی الزامیست",
|
||||
"name_fa": "نام فارسی",
|
||||
"name_fa_error": "وارد کردن نام فارسی الزامیست",
|
||||
"permission": "دسترسی",
|
||||
"permission_min_error": "حداقل باید یک دسترسی انتخاب شود",
|
||||
"phone_number": "شماره تلفن",
|
||||
"phone_number_positive": "شماره تلفن باید مثبت باشد",
|
||||
"phone_number_error": "وارد کردن شماره تلفن الزامیست",
|
||||
"phone_number_number": "شماره تلفن باید شامل اعداد باشد",
|
||||
"phone_number_max": "شماره تلفن باید شامل 11 رقم باشد",
|
||||
"national_id_positive": "کد ملی باید مثبت باشد",
|
||||
"national_id_number": "کد ملی باید شامل اعداد باشد",
|
||||
"national_id_max": "کد ملی باید شامل 10 رقم باشد",
|
||||
"national_id": "کد ملی",
|
||||
"national_id_error": "وارد کردن کد ملی الزامیست",
|
||||
"type_id_error": "وارد کردن نوع کاربر الزامیست",
|
||||
"navgan_id_error": "وارد کردن کد ناوگان الزامیست",
|
||||
"refahi": "رفاهی",
|
||||
"navgan": "ناوگان",
|
||||
"type_id": "نوع کاربر",
|
||||
"navgan_id": "کد ناوگان",
|
||||
"button-cancel": "انصراف",
|
||||
"loading_permissions_list": "درحال دریافت لیست دسترسی ها",
|
||||
"button-add": "ثبت"
|
||||
},
|
||||
"UpdateDialog": {
|
||||
"update": "ویرایش",
|
||||
"description": "توضیحات خود را وارد نمائید",
|
||||
"description_error": "وارد کردن توضیحات الزامی است!",
|
||||
"next-state-id": "وضعیت",
|
||||
"next-state-id-error": "وارد کردن وضعیت الزامیست",
|
||||
"update-tooltip": "ویرایش",
|
||||
"button-cancel": "بستن",
|
||||
"refahi": "رفاهی",
|
||||
"navgan": "ناوگان",
|
||||
"phone_number": "شماره تلفن",
|
||||
"national_id": "کد ملی",
|
||||
"name_en": "نام انگلیسی",
|
||||
"name_en_error": "وارد کردن نام انگلیسی الزامیست",
|
||||
"name_fa": "نام فارسی",
|
||||
"name_fa_error": "وارد کردن نام فارسی الزامیست",
|
||||
"permission": "دسترسی",
|
||||
"permission_min_error": "حداقل باید یک دسترسی انتخاب شود",
|
||||
"type_id": "نوع کاربر",
|
||||
"navgan_id": "کد ناوگان",
|
||||
"loading_permissions_list": "درحال دریافت لیست دسترسی ها",
|
||||
"button-update": "ثبت"
|
||||
},
|
||||
"DeleteDialog": {
|
||||
"delete": "حذف",
|
||||
"button-cancel": "انصراف",
|
||||
"typography": "آیا از حدف این مورد اطمینان دارید ؟",
|
||||
"button-delete": "حذف کردن"
|
||||
},
|
||||
"ExpertMangement": {
|
||||
"id": "کد یکتا",
|
||||
"name": "نام کامل",
|
||||
"username": "نام کاربری",
|
||||
"email": "پست الکترونیک",
|
||||
"phone_number": "شماره همراه",
|
||||
"national_id": "کد ملی",
|
||||
"position": "سمت",
|
||||
"province_fa": "استان",
|
||||
"role_name": "نقش",
|
||||
"gender": "جنسیت",
|
||||
"male": "مرد",
|
||||
"female": "زن",
|
||||
"updated_at": "آخرین بروزرسانی",
|
||||
"create": "افزودن کارشناس",
|
||||
"personal_info": "مشخصات کارشناس",
|
||||
"user_info": "اطلاعات کاربری",
|
||||
"rest_info": "اطلاعات تکمیلی",
|
||||
"text_field_full_name": "نام کامل",
|
||||
"text_field_username": "نام کاربری",
|
||||
"text_field_email": "پست الکترونیک",
|
||||
"text_field_phone_number": "شماره همراه",
|
||||
"text_field_telephone_id": "کد تلفن",
|
||||
"text_field_gender": "جنسیت",
|
||||
"text_field_national_id": "کد ملی",
|
||||
"text_field_password": "رمز عبور",
|
||||
"text_field_position": "سمت",
|
||||
"text_field_province_id": "استان",
|
||||
"text_field_roles": "نقش",
|
||||
"text_field_loading_provinces_list": "درحال دریافت شهر ها",
|
||||
"text_field_error_fetching_provinces": "خطا در دریافت شهر ها",
|
||||
"text_field_loading_roles_list": "درحال دریافت نقش ها",
|
||||
"text_field_error_fetching_roles": "خطا در دریافت نقش ها",
|
||||
"text_field_please_select_province": "ابتدا استان خود را انتخاب کنید",
|
||||
"text_field_loading_cities_list": "درحال دریافت شهر ها",
|
||||
"text_field_error_fetching_cities": "خطا در دریافت شهر ها",
|
||||
"text_field_new_password": "رمز عبور جدید",
|
||||
"error_message_full_name": "نام کامل خود را وارد کنید",
|
||||
"error_message_username": "نام کاربری خود را وارد کنید",
|
||||
"error_message_email": "پست الکترونیک خود را وارد کنید",
|
||||
"error_message_phone_number": "شماره همراه خود را وارد کنید",
|
||||
"error_message_telephone_id": "کد تلفن خود را وارد کنید",
|
||||
"error_message_gender": "جنسیت خود را وارد کنید",
|
||||
"error_message_national_id": "کد ملی خود را وارد کنید",
|
||||
"error_message_password": "رمز عبور خود را وارد کنید",
|
||||
"error_message_password_regex": "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد",
|
||||
"error_message_position": "سمت خود را وارد کنید",
|
||||
"error_message_province_id": "استان خود را وارد کنید",
|
||||
"error_message_roles": "نقش خود را وارد کنید",
|
||||
"error_message_new_password": "رمز عبور جدید را وارد کنید",
|
||||
"error_message_new_password_regex": "رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد",
|
||||
"button_cancel": "بستن",
|
||||
"button_confirm": "ثبت",
|
||||
"delete_expert": "حذف کارشناس",
|
||||
"are_you_sure_text": "آیا از انجام این عملیات اطمینان دارید؟",
|
||||
"button_delete": "حذف",
|
||||
"delete_tooltip": "حذف",
|
||||
"update_tooltip": "ویرایش",
|
||||
"update_expert": "ویرایش کارشناس"
|
||||
},
|
||||
"CallHistory": {
|
||||
"category_name": "موضوع",
|
||||
"subcategory_name": "زیر موضوع",
|
||||
"operator": "اپراتور",
|
||||
"date": "تاریخ",
|
||||
"call_history_of": "تاریخچه تماس های",
|
||||
"call_history_not_found": "تاریخچه ای برای تماس دریافتی یافت نشد",
|
||||
"call_history_error_fetching": "خطا در دریافت تاریخچه تماس دریافتی",
|
||||
"show_more": "نمایش موارد بیشتر"
|
||||
},
|
||||
"CallAction": {
|
||||
"call_history_of": "عملیات های مربوط به تماس",
|
||||
"categories" : "موضوع ها",
|
||||
"subcategories" : "زیر موضوع ها",
|
||||
"description" : "توضیحات تماس (اختیاری)",
|
||||
"text_field_label" : "توضیحات",
|
||||
"text_field_palacholder" : "لطفا توضیحات خود را وارد نمایید"
|
||||
}
|
||||
}
|
||||
92
public/locales/fa/datatable.js
Normal file
92
public/locales/fa/datatable.js
Normal file
@@ -0,0 +1,92 @@
|
||||
export const FA_DATATABLE_LOCALIZATION = {
|
||||
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: "بدون مرتب سازی",
|
||||
};
|
||||
57
public/manifest.json
Normal file
57
public/manifest.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"short_name": "CRM Dashboard",
|
||||
"name": "CRM Expert Dashboard",
|
||||
"description": "CRM",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
import { render, screen, waitFor, fireEvent , act } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import ChangePasswordForm from "@/components/dashboard/change-password/change-password-form";
|
||||
import {SET_USER_PASSWORD} from "@/core/data/apiRoutes";
|
||||
import {server} from "../../../../../../mocks/server";
|
||||
import {rest} from "msw";
|
||||
|
||||
describe('Change Password Form Component From Change Password Page', () => {
|
||||
describe('Rendering', () => {
|
||||
it('Should see change password heading',() => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const changePasswordElement = screen.getByRole('heading', { level: 4 });
|
||||
expect(changePasswordElement).toHaveTextContent('تغییر رمز عبور');
|
||||
});
|
||||
it('Should see the label for current password field', () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const currentPasswordLabel = screen.queryByLabelText('رمز عبور فعلی');
|
||||
expect(currentPasswordLabel).toBeInTheDocument();
|
||||
});
|
||||
it('Should see the label for new password field', () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const newPasswordLabel = screen.queryByLabelText('رمز عبور جدید');
|
||||
expect(newPasswordLabel).toBeInTheDocument();
|
||||
});
|
||||
it('Should see the label for confirm password field', () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const confirmPasswordLabel = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
expect(confirmPasswordLabel).toBeInTheDocument();
|
||||
});
|
||||
it('Should see the submit button with the submit label and should be disable', () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
expect(submitButton).toBeInTheDocument();
|
||||
expect(submitButton).toBeDisabled();
|
||||
});
|
||||
it('Should have empty input fields and not see any validation error for current password, new password, and confirm password', () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
expect(currentPasswordInput).toHaveValue('');
|
||||
expect(newPasswordInput).toHaveValue('');
|
||||
expect(confirmPasswordInput).toHaveValue('');
|
||||
|
||||
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
|
||||
|
||||
});
|
||||
});
|
||||
describe("Behavior", ()=>{
|
||||
it('Should fill the current password field and not see any error while its not empty', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
|
||||
// Simulate typing something in the current password input
|
||||
fireEvent.change(currentPasswordInput, { target: { value: 'witel@fani0' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).not.toBeInTheDocument();
|
||||
expect(currentPasswordInput).toHaveValue('witel@fani0');
|
||||
});
|
||||
});
|
||||
it('Should fill the new password field and not see any error while its not empty', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
|
||||
// Simulate typing something in the new password input
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'witel@fani1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
|
||||
expect(newPasswordInput).toHaveValue('witel@fani1');
|
||||
});
|
||||
});
|
||||
it('Should fill the confirm new password field and not see any error while its not empty', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
// Simulate typing something in the confirmation new password input
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'witel@fani1' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).not.toBeInTheDocument();
|
||||
expect(confirmPasswordInput).toHaveValue('witel@fani1');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Validation", ()=>{
|
||||
it('Should see error while current password is empty on blur event', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
// Simulate blur event on the current password input
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
|
||||
// Clear the input field
|
||||
fireEvent.change(currentPasswordInput, { target: { value: '' } });
|
||||
|
||||
fireEvent.blur(currentPasswordInput);
|
||||
|
||||
await waitFor(()=>{
|
||||
expect(screen.queryByText("وارد کردن رمز عبور فعلی الزامیست!")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should see error while new password is empty on blur event', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
// Simulate blur event on the new password input
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
|
||||
// Clear the input field
|
||||
fireEvent.change(newPasswordInput, { target: { value: '' } });
|
||||
|
||||
fireEvent.blur(newPasswordInput);
|
||||
|
||||
await waitFor(()=>{
|
||||
expect(screen.queryByText("وارد کردن رمز عبور جدید الزامیست!")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should see error while confirm new password is empty on blur event', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
// Simulate blur event on the new password input
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
// Clear the input field
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: '' } });
|
||||
|
||||
fireEvent.blur(confirmPasswordInput);
|
||||
|
||||
await waitFor(()=>{
|
||||
expect(screen.queryByText("وارد کردن تکرار رمز عبور جدید الزامیست!")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should see error when new password is less than 8 characters', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
|
||||
// Simulate entering a short new password
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'test' } });
|
||||
fireEvent.blur(newPasswordInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Simulate clicking the submit button
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('Should not see error when new password are 8 or more characters', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
|
||||
// Simulate entering a valid new password
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.blur(newPasswordInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Simulate clicking the submit button
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر باشد.")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('Should see error when new password and confirm password do not match on blur event and submit click', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
|
||||
// Simulate entering a valid new password
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.blur(newPasswordInput);
|
||||
|
||||
// Simulate entering a different value in the confirm password field
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'MismatchedPassword' } });
|
||||
fireEvent.blur(confirmPasswordInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Simulate clicking the submit button
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('Should not see error when new password and confirm password match on blur event and submit click', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
|
||||
// Simulate entering a valid new password
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.blur(newPasswordInput);
|
||||
|
||||
// Simulate entering the same value in the confirmation password field
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.blur(confirmPasswordInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Simulate clicking the submit button
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("پسورد و تکرار رمز عبور باید یکسان باشد")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Form Submission", () => {
|
||||
it('Should enable the submit button when the inputs are valid', async () => {
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
|
||||
// Simulate entering valid values in the form fields
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
|
||||
// Check if the submit button is enabled
|
||||
await waitFor(() => {
|
||||
expect(submitButton).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
it('Should request to api and resetform in success response', async () => {
|
||||
// Render the component
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
|
||||
// Fill in the form fields
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
fireEvent.change(currentPasswordInput, { target: { value: 'Witel@fani0' } });
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
|
||||
// Submit the form
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
await userEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(currentPasswordInput).toHaveValue('');
|
||||
expect(newPasswordInput).toHaveValue('');
|
||||
expect(confirmPasswordInput).toHaveValue('');
|
||||
});
|
||||
});
|
||||
it('Should request to api and not resetform in error response', async () => {
|
||||
// Render the component
|
||||
render(<MockAppWithProviders><ChangePasswordForm /></MockAppWithProviders>);
|
||||
server.use([rest.get(SET_USER_PASSWORD, (req, res, ctx) => {
|
||||
return res(ctx.status(422))
|
||||
})])
|
||||
|
||||
// Fill in the form fields wrong
|
||||
const currentPasswordInput = screen.queryByLabelText('رمز عبور فعلی');
|
||||
const newPasswordInput = screen.queryByLabelText('رمز عبور جدید');
|
||||
const confirmPasswordInput = screen.queryByLabelText('تکرار رمز عبور جدید');
|
||||
|
||||
fireEvent.change(currentPasswordInput, { target: { value: 'incorrect' } });
|
||||
fireEvent.change(newPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: 'Witel@fani1' } });
|
||||
|
||||
// Submit the form
|
||||
const submitButton = screen.getByRole('button', { name: 'ثبت' });
|
||||
await userEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(currentPasswordInput.value).toBe('incorrect');
|
||||
expect(newPasswordInput.value).toBe('Witel@fani1');
|
||||
expect(confirmPasswordInput.value).toBe('Witel@fani1');
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -0,0 +1,137 @@
|
||||
import {Formik, Form} from "formik";
|
||||
import * as Yup from "yup";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {Button, Paper, Stack, Typography} from "@mui/material";
|
||||
import PasswordField from "@/core/components/PasswordField";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import useRequest from "@/lib/app/hooks/useRequest";
|
||||
import {SET_USER_PASSWORD} from "@/core/data/apiRoutes";
|
||||
|
||||
const ChangePasswordForm = ({onSubmit}) => {
|
||||
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_current_password_required")
|
||||
),
|
||||
new_password: Yup.string()
|
||||
.min(8, t("ChangePassword.error_message_password_length"))
|
||||
.required(t("ChangePassword.error_message_new_password_required")),
|
||||
new_password_confirmation: Yup.string()
|
||||
.required(t("ChangePassword.error_message_confirm_password_required"))
|
||||
.test(
|
||||
t("ChangePassword.error_message_password_match"),
|
||||
t("ChangePassword.error_message_password_not_match"), // Use the correct error message here
|
||||
function (value) {
|
||||
return this.parent.new_password === value;
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleSubmit}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
{(props) => (
|
||||
<StyledForm
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
props.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<Paper elevation={0}>
|
||||
<Stack spacing={3} sx={{p: 5}} component="div">
|
||||
<Typography margin={2} variant="h4" textAlign="center">
|
||||
{t("ChangePassword.typography_change_password")}
|
||||
</Typography>
|
||||
<Stack spacing={1} component="div">
|
||||
<PasswordField
|
||||
name="current_password"
|
||||
label={t("ChangePassword.label_current_password")}
|
||||
error={
|
||||
props.touched.current_password &&
|
||||
props.errors.current_password
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.current_password
|
||||
? props.errors.current_password
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack spacing={1} component="div">
|
||||
<PasswordField
|
||||
name="new_password"
|
||||
label={t("ChangePassword.label_new_password")}
|
||||
error={
|
||||
props.touched.new_password && props.errors.new_password
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.new_password ? props.errors.new_password : null
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack spacing={1} component="div">
|
||||
<PasswordField
|
||||
name="new_password_confirmation"
|
||||
label={t("ChangePassword.label_confirm_password")}
|
||||
error={
|
||||
props.touched.new_password_confirmation &&
|
||||
props.errors.new_password_confirmation
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.new_password_confirmation
|
||||
? props.errors.new_password_confirmation
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="large"
|
||||
disabled={props.isSubmitting || !(props.values.current_password && props.values.new_password && props.values.new_password_confirmation)}
|
||||
>
|
||||
{props.isSubmitting
|
||||
? t("SubmitButton.button_while_submit")
|
||||
: t("SubmitButton.button_submit")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</StyledForm>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangePasswordForm;
|
||||
18
src/components/dashboard/change-password/index.jsx
Normal file
18
src/components/dashboard/change-password/index.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import CenterLayout from "@/layouts/CenterLayout";
|
||||
import DashboardLayout from "@/layouts/DashboardLayout";
|
||||
import {Container} from "@mui/material";
|
||||
import ChangePasswordForm from "@/components/dashboard/change-password/change-password-form";
|
||||
|
||||
const DashboardChangePasswordComponent = () => {
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<CenterLayout>
|
||||
<Container maxWidth="sm">
|
||||
<ChangePasswordForm />
|
||||
</Container>
|
||||
</CenterLayout>
|
||||
</DashboardLayout>
|
||||
);
|
||||
};
|
||||
export default DashboardChangePasswordComponent;
|
||||
223
src/components/dashboard/edit-profile/index.jsx
Normal file
223
src/components/dashboard/edit-profile/index.jsx
Normal file
@@ -0,0 +1,223 @@
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import CenterLayout from "@/layouts/CenterLayout";
|
||||
import DashboardLayout from "@/layouts/DashboardLayout";
|
||||
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 (
|
||||
<DashboardLayout>
|
||||
<CenterLayout>
|
||||
<Container maxWidth="sm">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleSubmit}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
{(props) => (
|
||||
<StyledForm
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
props.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<Paper elevation={0}>
|
||||
<Stack spacing={3} sx={{p: 5}} component="div">
|
||||
<Typography margin={2} variant="h4" textAlign="center">
|
||||
{t("UpdateProfile.typography_edit_profile")}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<AvatarUpload
|
||||
user={user}
|
||||
setFieldValue={props.setFieldValue}
|
||||
valueAvatar="expert_avatar"
|
||||
changeFlag="change_avatar"
|
||||
/>
|
||||
</Box>
|
||||
<Grid container spacing={2} sx={{pb: 2}}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Field
|
||||
as={TextField}
|
||||
name="username"
|
||||
label={t("UpdateProfile.text_field_username")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
disabled={true}
|
||||
error={
|
||||
props.touched.username && props.errors.username
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.username
|
||||
? props.errors.username
|
||||
: null
|
||||
}
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Field
|
||||
as={TextField}
|
||||
name="name"
|
||||
label={t("UpdateProfile.text_field_name")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
disabled={true}
|
||||
error={
|
||||
props.touched.name && props.errors.name
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.name ? props.errors.name : null
|
||||
}
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Field
|
||||
as={TextField}
|
||||
name="email"
|
||||
label={t("UpdateProfile.text_field_email")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
disabled={true}
|
||||
error={
|
||||
props.touched.email && props.errors.email
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.email ? props.errors.email : null
|
||||
}
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Field
|
||||
as={TextField}
|
||||
name="province_name"
|
||||
label={t("UpdateProfile.text_field_province_name")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
disabled={true}
|
||||
error={
|
||||
props.touched.province_name &&
|
||||
props.errors.province_name
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.province_name
|
||||
? props.errors.province_name
|
||||
: null
|
||||
}
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Field
|
||||
as={TextField}
|
||||
name="position"
|
||||
label={t("UpdateProfile.text_field_position")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
disabled={true}
|
||||
error={
|
||||
props.touched.position && props.errors.position
|
||||
? true
|
||||
: false
|
||||
}
|
||||
helperText={
|
||||
props.touched.position
|
||||
? props.errors.position
|
||||
: null
|
||||
}
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</StyledForm>
|
||||
)}
|
||||
</Formik>
|
||||
</Container>
|
||||
</CenterLayout>
|
||||
</DashboardLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardEditProfile;
|
||||
@@ -0,0 +1,33 @@
|
||||
import {render, screen} from "@testing-library/react";
|
||||
import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
|
||||
import ExpertManagementDataTable from "@/components/dashboard/expert-management/DataTable";
|
||||
|
||||
describe("ExpertManagementDatatable Component From Expert Management", () => {
|
||||
describe("Rendering", () => {
|
||||
it("Table Headers Rendered", () => {
|
||||
render(<MockAppWithProviders><ExpertManagementDataTable/></MockAppWithProviders>);
|
||||
const idHeader = screen.queryByText("کد یکتا");
|
||||
const nameHeader = screen.queryByText("نام کامل");
|
||||
const usernameHeader = screen.queryByText("نام کاربری");
|
||||
const emailHeader = screen.queryByText("پست الکترونیک");
|
||||
const phone_numberHeader = screen.queryByText("شماره همراه");
|
||||
const national_idHeader = screen.queryByText("کد ملی");
|
||||
const positionHeader = screen.queryByText("سمت");
|
||||
const province_nameHeader = screen.queryByText("استان");
|
||||
const role_nameHeader = screen.queryByText("نقش");
|
||||
const genderHeader = screen.queryByText("جنسیت");
|
||||
const updated_atHeader = screen.queryByText("آخرین بروزرسانی");
|
||||
expect(idHeader).toBeInTheDocument();
|
||||
expect(nameHeader).toBeInTheDocument();
|
||||
expect(usernameHeader).toBeInTheDocument();
|
||||
expect(emailHeader).toBeInTheDocument();
|
||||
expect(phone_numberHeader).toBeInTheDocument();
|
||||
expect(national_idHeader).toBeInTheDocument();
|
||||
expect(positionHeader).toBeInTheDocument();
|
||||
expect(province_nameHeader).toBeInTheDocument();
|
||||
expect(role_nameHeader).toBeInTheDocument();
|
||||
expect(genderHeader).toBeInTheDocument();
|
||||
expect(updated_atHeader).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
190
src/components/dashboard/expert-management/DataTable/index.jsx
Normal file
190
src/components/dashboard/expert-management/DataTable/index.jsx
Normal file
@@ -0,0 +1,190 @@
|
||||
import DataTable from "@/core/components/DataTable";
|
||||
import MuiDatePicker from "@/core/components/MuiDatePicker";
|
||||
import {GET_EXPERTS} from "@/core/data/apiRoutes";
|
||||
import TableToolbar from "../TableToolbar";
|
||||
import TableRowActions from "../TableRowActions";
|
||||
import {Box, Typography} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {useMemo} from "react";
|
||||
import moment from "jalali-moment";
|
||||
|
||||
function ExpertManagementDataTable() {
|
||||
const t = useTranslations();
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorFn: (row) => row.id,
|
||||
id: "id",
|
||||
header: t("ExpertMangement.id"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains",
|
||||
"lessThan",
|
||||
"greaterThan",
|
||||
"between",
|
||||
],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.full_name,
|
||||
id: "full_name",
|
||||
header: t("ExpertMangement.name"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.username,
|
||||
id: "username",
|
||||
header: t("ExpertMangement.username"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.email,
|
||||
id: "email",
|
||||
header: t("ExpertMangement.email"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.phone_number,
|
||||
id: "phone_number",
|
||||
header: t("ExpertMangement.phone_number"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.national_id,
|
||||
id: "national_id",
|
||||
header: t("ExpertMangement.national_id"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.position,
|
||||
id: "position",
|
||||
header: t("ExpertMangement.position"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.province_fa,
|
||||
id: "province_id",
|
||||
header: t("ExpertMangement.province_fa"),
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.roles[0]?.name_fa,
|
||||
id: "roles[0].name_fa",
|
||||
header: t("ExpertMangement.role_name"),
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography variant="body2">{renderedCellValue}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.gender,
|
||||
id: "gender",
|
||||
header: t("ExpertMangement.gender"),
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: ["contains", "equals", "notEquals"],
|
||||
Cell: ({renderedCellValue}) => (
|
||||
<Typography
|
||||
variant="body2">{renderedCellValue === "male" ? t("ExpertMangement.male") : t("ExpertMangement.female")}</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) =>
|
||||
moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
id: "updated_at",
|
||||
header: t("ExpertMangement.updated_at"),
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterFn: "lessThan",
|
||||
columnFilterModeOptions: ["lessThan", "greaterThan"],
|
||||
Cell: ({renderedCellValue}) => {
|
||||
return <Typography variant="body2">{renderedCellValue}</Typography>;
|
||||
},
|
||||
Header: ({column}) => <>{column.columnDef.header}</>,
|
||||
Filter: ({column}) => {
|
||||
return (
|
||||
<MuiDatePicker column={column}/>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
return (
|
||||
<Box sx={{px: 3}}>
|
||||
<DataTable
|
||||
tableUrl={GET_EXPERTS}
|
||||
columns={columns}
|
||||
selectableRow={false}
|
||||
CustomToolbar={TableToolbar}
|
||||
enableCustomToolbar={true}
|
||||
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}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ExpertManagementDataTable;
|
||||
@@ -0,0 +1,7 @@
|
||||
const ChangePassword = () => {
|
||||
return (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChangePassword
|
||||
@@ -0,0 +1,219 @@
|
||||
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
|
||||
import React from 'react';
|
||||
import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
|
||||
import * as Yup from "yup";
|
||||
import {Formik} from "formik";
|
||||
import PersonalInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo";
|
||||
import {useTranslations} from "next-intl";
|
||||
import Province from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province";
|
||||
|
||||
|
||||
const CreateFormMock = ({Component}) => {
|
||||
const t = useTranslations();
|
||||
const validationSchema = Yup.object().shape({
|
||||
full_name: Yup.string().required(t("ExpertMangement.error_message_full_name")),
|
||||
email: Yup.string().required(t("ExpertMangement.error_message_email")),
|
||||
phone_number: Yup.string().required(t("ExpertMangement.error_message_phone_number")),
|
||||
telephone_id: Yup.string().required(t("ExpertMangement.error_message_telephone_id")),
|
||||
national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
|
||||
gender: Yup.string().required(t("ExpertMangement.error_message_gender"))
|
||||
});
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
full_name: "",
|
||||
email: "",
|
||||
phone_number: "",
|
||||
telephone_id: "",
|
||||
national_id: "",
|
||||
gender: ""
|
||||
}}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={(values, {}) => {
|
||||
}}
|
||||
>
|
||||
{formikProps => (<Component formik={formikProps}></Component>)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
describe("PersonalInfo Component From Expert Management (create)", () => {
|
||||
describe("Rendering", () => {
|
||||
it("full_name TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const fullNameTextField = screen.queryByLabelText('نام کامل');
|
||||
expect(fullNameTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("Email TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const emailTextField = screen.queryByLabelText('پست الکترونیک');
|
||||
expect(emailTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("Phone Number TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
|
||||
expect(phoneNumberTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("telephone id TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
|
||||
expect(telephoneIdTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("National Id TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const nationalIdTextField = screen.queryByLabelText('کد ملی');
|
||||
expect(nationalIdTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("Gender Select Box Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const genderSelectBox = screen.getByTestId('select-box');
|
||||
expect(genderSelectBox).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Behavioral", () => {
|
||||
it("Name TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const nameTextField = screen.queryByLabelText('نام کامل');
|
||||
fireEvent.change(nameTextField, {target: {value: 'exampleName'}});
|
||||
await act(() => {
|
||||
expect(nameTextField).toHaveValue('exampleName');
|
||||
})
|
||||
});
|
||||
it("Email TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const emailTextField = screen.queryByLabelText('پست الکترونیک');
|
||||
fireEvent.change(emailTextField, {target: {value: 'exampleEmail'}});
|
||||
await act(() => {
|
||||
expect(emailTextField).toHaveValue('exampleEmail');
|
||||
})
|
||||
});
|
||||
it("Phone Number TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
|
||||
fireEvent.change(phoneNumberTextField, {target: {value: 'examplePhoneNumber'}});
|
||||
await act(() => {
|
||||
expect(phoneNumberTextField).toHaveValue('examplePhoneNumber');
|
||||
})
|
||||
});
|
||||
it("Telephone Id TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
|
||||
fireEvent.change(telephoneIdTextField, {target: {value: 'exampleTelephoneId'}});
|
||||
await act(() => {
|
||||
expect(telephoneIdTextField).toHaveValue('exampleTelephoneId');
|
||||
})
|
||||
});
|
||||
it("National Id TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const nationalIdTextField = screen.queryByLabelText('کد ملی');
|
||||
fireEvent.change(nationalIdTextField, {target: {value: 'exampleNationalId'}});
|
||||
await act(() => {
|
||||
expect(nationalIdTextField).toHaveValue('exampleNationalId');
|
||||
})
|
||||
});
|
||||
it("Gender Select Box Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const genderSelectBox = screen.getByTestId('select-box');
|
||||
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(genderSelectBox).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.mouseDown(genderSelectOpener);
|
||||
await waitFor(() => {
|
||||
const selectItem = screen.queryByText("مرد");
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
describe("validation", () => {
|
||||
it('Should See Error When Name Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
|
||||
const nameInput = screen.queryByLabelText('نام کامل');
|
||||
|
||||
fireEvent.change(nameInput, {target: {value: ''}});
|
||||
fireEvent.blur(nameInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("نام کامل خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When Email Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
|
||||
const emailInput = screen.queryByLabelText('پست الکترونیک');
|
||||
|
||||
fireEvent.change(emailInput, {target: {value: ''}});
|
||||
fireEvent.blur(emailInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("پست الکترونیک خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When Phone Number Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
|
||||
const phoneNumberInput = screen.queryByLabelText('شماره همراه');
|
||||
|
||||
fireEvent.change(phoneNumberInput, {target: {value: ''}});
|
||||
fireEvent.blur(phoneNumberInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("شماره همراه خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When telephone Id Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
|
||||
const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
|
||||
|
||||
fireEvent.change(telephoneIdTextField, {target: {value: ''}});
|
||||
fireEvent.blur(telephoneIdTextField);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("کد تلفن خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When National Id Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
|
||||
const nationalIdInput = screen.queryByLabelText('کد ملی');
|
||||
|
||||
fireEvent.change(nationalIdInput, {target: {value: ''}});
|
||||
fireEvent.blur(nationalIdInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("کد ملی خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should Select An Item With Valid Value of gender', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PersonalInfo}/></MockAppWithProviders>);
|
||||
const genderInput = screen.getByTestId("input-gender")
|
||||
const genderSelectOpener = await waitFor(() => screen.getByTestId("option-opener-gender"));
|
||||
|
||||
fireEvent.mouseDown(genderSelectOpener);
|
||||
const selectItem = await waitFor(() => screen.queryByText("مرد"));
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
fireEvent.click(selectItem);
|
||||
await waitFor(() => {
|
||||
expect(genderInput.value).toBe('male')
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextField} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
|
||||
const PersonalInfo = ({formik}) => {
|
||||
const t = useTranslations();
|
||||
|
||||
const genderList = [
|
||||
{id: 1, name_en: "male", name_fa: "مرد"},
|
||||
{id: 2, name_en: "female", name_fa: "زن"}
|
||||
]
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<TextField
|
||||
name="full_name"
|
||||
label={t("ExpertMangement.text_field_full_name")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.full_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.full_name && !!formik.errors.full_name}
|
||||
helperText={formik.touched.full_name && formik.errors.full_name ? formik.errors.full_name : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<TextField
|
||||
name="national_id"
|
||||
label={t("ExpertMangement.text_field_national_id")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.national_id}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.national_id && !!formik.errors.national_id}
|
||||
helperText={formik.touched.national_id && formik.errors.national_id ? formik.errors.national_id : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<TextField
|
||||
name="phone_number"
|
||||
label={t("ExpertMangement.text_field_phone_number")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.phone_number}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.phone_number && !!formik.errors.phone_number}
|
||||
helperText={formik.touched.phone_number && formik.errors.phone_number ? formik.errors.phone_number : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<TextField
|
||||
name="email"
|
||||
label={t("ExpertMangement.text_field_email")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.email}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.email && !!formik.errors.email}
|
||||
helperText={formik.touched.email && formik.errors.email ? formik.errors.email : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<TextField
|
||||
name="telephone_id"
|
||||
label={t("ExpertMangement.text_field_telephone_id")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.telephone_id}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.telephone_id && !!formik.errors.telephone_id}
|
||||
helperText={formik.touched.telephone_id && formik.errors.telephone_id ? formik.errors.telephone_id : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<FormControl
|
||||
error={formik.touched.gender && !!formik.errors.gender}
|
||||
sx={{width: "100%", mt: 2}}
|
||||
size="small"
|
||||
>
|
||||
<InputLabel>{t("ExpertMangement.text_field_gender")}</InputLabel>
|
||||
<Select
|
||||
name="gender"
|
||||
label={t("ExpertMangement.text_field_gender")}
|
||||
value={formik.values.gender}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("gender", e.target.value);
|
||||
}}
|
||||
inputProps={{
|
||||
"data-testid": "input-gender"
|
||||
}}
|
||||
data-testid="select-box"
|
||||
SelectDisplayProps={{"data-testid": 'option-opener-gender'}}
|
||||
onBlur={formik.handleBlur}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
>
|
||||
{(
|
||||
genderList.map((item) => (
|
||||
<MenuItem key={item.id} value={item.name_en}>
|
||||
{item.name_fa}
|
||||
</MenuItem>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.touched.gender && formik.errors.gender ? formik.errors.gender : ""}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
export default PersonalInfo
|
||||
@@ -0,0 +1,96 @@
|
||||
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
|
||||
import React from 'react';
|
||||
import {useTranslations} from "next-intl";
|
||||
import * as Yup from "yup";
|
||||
import {Formik} from "formik";
|
||||
import MockAppWithProviders from "../../../../../../../../../../mocks/AppWithProvider";
|
||||
import PositionAndRole from "../../PositionAndRole";
|
||||
|
||||
const CreateFormMock = ({Component}) => {
|
||||
const t = useTranslations();
|
||||
const validationSchema = Yup.object().shape({
|
||||
position: Yup.string().required(t("ExpertMangement.error_message_position")),
|
||||
roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
|
||||
});
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
position: "",
|
||||
roles: ""
|
||||
}}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={(values, {}) => {
|
||||
}}
|
||||
>
|
||||
{formikProps => (<Component formik={formikProps}></Component>)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
describe("PositionAndRole Component From Expert Management (create)", () => {
|
||||
describe("Rendering", () => {
|
||||
it("Position TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const positionTextField = screen.queryByLabelText('سمت');
|
||||
expect(positionTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("Role Select Box Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
const roleSelect = screen.getByTestId('select-box');
|
||||
await waitFor(() => {
|
||||
expect(roleSelect).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Behavioral", () => {
|
||||
it("Position TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
const positionTextField = screen.queryByLabelText('سمت');
|
||||
fireEvent.change(positionTextField, {target: {value: 'examplePosition'}});
|
||||
await waitFor(() => {
|
||||
expect(positionTextField).toHaveValue('examplePosition');
|
||||
})
|
||||
});
|
||||
it("Role Select Box Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
const roleSelect = screen.getByTestId("option-opener-role");
|
||||
await waitFor(() => {
|
||||
expect(roleSelect).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.mouseDown(roleSelect);
|
||||
await waitFor(() => {
|
||||
const selectItem = screen.queryByText("ادمین");
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("validation", () => {
|
||||
it('Should See Error When Position Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
|
||||
const positionInput = screen.queryByLabelText('سمت');
|
||||
|
||||
fireEvent.change(positionInput, {target: {value: ''}});
|
||||
fireEvent.blur(positionInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("سمت خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should Select An Item With Valid Value of role', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={PositionAndRole}/></MockAppWithProviders>);
|
||||
const roleInput = await waitFor(() => screen.getByTestId("input-role-id"));
|
||||
const roleSelectOpener = await waitFor(() => screen.getByTestId("option-opener-role"));
|
||||
|
||||
fireEvent.mouseDown(roleSelectOpener);
|
||||
const selectItem = await waitFor(() => screen.queryByText("ادمین"));
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
fireEvent.click(selectItem);
|
||||
await waitFor(() => {
|
||||
expect(roleInput.value).toBe('1')
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextField} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import useRequest from "@/lib/app/hooks/useRequest";
|
||||
import useRole from "@/lib/app/hooks/useRole";
|
||||
import {log} from "next/dist/server/typescript/utils";
|
||||
|
||||
const PositionAndRole = ({formik}) => {
|
||||
const t = useTranslations();
|
||||
const requestServer = useRequest()
|
||||
const {roleList, isLoadingRoleList, errorRoleList} = useRole();
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField
|
||||
name="position"
|
||||
label={t("ExpertMangement.text_field_position")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.position}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.position && !!formik.errors.position}
|
||||
helperText={formik.touched.position && formik.errors.position ? formik.errors.position : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<FormControl
|
||||
error={formik.touched.roles && !!formik.errors.roles}
|
||||
sx={{width: "100%", mt: 2}}
|
||||
size="small"
|
||||
>
|
||||
<InputLabel>{t("ExpertMangement.text_field_roles")}</InputLabel>
|
||||
<Select
|
||||
name="roles"
|
||||
label={t("ExpertMangement.text_field_roles")}
|
||||
value={formik.values.roles}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
fullWidth
|
||||
inputProps={{
|
||||
"data-testid": "input-role-id"
|
||||
}}
|
||||
data-testid="select-box"
|
||||
SelectDisplayProps={{"data-testid": 'option-opener-role'}}
|
||||
variant="outlined"
|
||||
>
|
||||
{isLoadingRoleList ? (
|
||||
<MenuItem>
|
||||
{t("ExpertMangement.text_field_loading_roles_list")}
|
||||
</MenuItem>
|
||||
) : errorRoleList ? (
|
||||
<MenuItem>
|
||||
{t("ExpertMangement.text_field_error_fetching_roles")}
|
||||
</MenuItem>
|
||||
) : (
|
||||
roleList.map((item) => (
|
||||
<MenuItem key={item.id} value={item.id}>
|
||||
{item.name_fa}
|
||||
</MenuItem>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.touched.roles && formik.errors.roles ? formik.errors.roles : ""}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
export default PositionAndRole
|
||||
@@ -0,0 +1,71 @@
|
||||
import {fireEvent, render, screen, waitFor} from "@testing-library/react";
|
||||
import React from 'react';
|
||||
import {useTranslations} from "next-intl";
|
||||
import * as Yup from "yup";
|
||||
import {Formik} from "formik";
|
||||
import Province from "../../Province";
|
||||
import MockAppWithProviders from "../../../../../../../../../../mocks/AppWithProvider";
|
||||
|
||||
const CreateFormMock = ({Component}) => {
|
||||
const t = useTranslations();
|
||||
const validationSchema = Yup.object().shape({
|
||||
province_id: Yup.string().required(t("ExpertMangement.error_message_province_id")),
|
||||
});
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
province_id: "",
|
||||
}}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={(values, {}) => {
|
||||
}}
|
||||
>
|
||||
{formikProps => (<Component formik={formikProps}></Component>)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
describe("Province Component From Expert Management (create)", () => {
|
||||
describe("Rendering", () => {
|
||||
it("Province Select Box Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const provinceSelectBox = screen.getByTestId('select-box');
|
||||
expect(provinceSelectBox).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Behavioral", () => {
|
||||
it("Province Select Box Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
|
||||
const provinceSelectBox = screen.getByTestId('select-box');
|
||||
const provinceSelectOpener = await waitFor(() => screen.getByTestId("option-opener-province"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(provinceSelectBox).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.mouseDown(provinceSelectOpener);
|
||||
await waitFor(() => {
|
||||
const selectItem = screen.queryByText("آذربایجان شرقی");
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
describe("validation", () => {
|
||||
it('Should Select An Item With Valid Value of province', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={Province}/></MockAppWithProviders>);
|
||||
const provinceInput = screen.getByTestId("input-province-id")
|
||||
const provinceSelectOpener = await waitFor(() => screen.getByTestId("option-opener-province"));
|
||||
|
||||
fireEvent.mouseDown(provinceSelectOpener);
|
||||
const selectItem = await waitFor(() => screen.queryByText("آذربایجان شرقی"));
|
||||
expect(selectItem).toBeInTheDocument();
|
||||
fireEvent.click(selectItem);
|
||||
await waitFor(() => {
|
||||
expect(provinceInput.value).toBe('1')
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import {FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import useProvince from "@/lib/app/hooks/useProvince";
|
||||
import useRequest from "@/lib/app/hooks/useRequest";
|
||||
|
||||
const Province = ({formik}) => {
|
||||
const t = useTranslations();
|
||||
const requestServer = useRequest()
|
||||
const {provinceList, isLoadingProvinceList, errorProvinceList} = useProvince();
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<FormControl
|
||||
error={formik.touched.province_id && !!formik.errors.province_id}
|
||||
sx={{width: "100%", mt: 2}}
|
||||
size="small"
|
||||
>
|
||||
<InputLabel>{t("ExpertMangement.text_field_province_id")}</InputLabel>
|
||||
<Select
|
||||
name="province_id"
|
||||
disabled={isLoadingProvinceList || errorProvinceList}
|
||||
label={t("ExpertMangement.text_field_province_id")}
|
||||
value={formik.values.province_id}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("province_id", e.target.value);
|
||||
}}
|
||||
inputProps={{
|
||||
"data-testid": "input-province-id"
|
||||
}}
|
||||
data-testid="select-box"
|
||||
SelectDisplayProps={{"data-testid": 'option-opener-province'}}
|
||||
onBlur={formik.handleBlur}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
>
|
||||
{isLoadingProvinceList ? (
|
||||
<MenuItem>
|
||||
{t("ExpertMangement.text_field_loading_provinces_list")}
|
||||
</MenuItem>
|
||||
) : errorProvinceList ? (
|
||||
<MenuItem>
|
||||
{t("ExpertMangement.text_field_error_fetching_provinces")}
|
||||
</MenuItem>
|
||||
) : (
|
||||
provinceList.map((item) => (
|
||||
<MenuItem key={item.id} value={item.id}>
|
||||
{item.name}
|
||||
</MenuItem>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.touched.province_id && formik.errors.province_id ? formik.errors.province_id : ""}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
export default Province
|
||||
@@ -0,0 +1,12 @@
|
||||
import Province from "./Province";
|
||||
import PositionAndRole from "./PositionAndRole";
|
||||
|
||||
const RestInfo = ({formik}) => {
|
||||
return (
|
||||
<>
|
||||
<Province formik={formik}/>
|
||||
<PositionAndRole formik={formik}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default RestInfo
|
||||
@@ -0,0 +1,123 @@
|
||||
import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
|
||||
import React from 'react';
|
||||
import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
|
||||
import {useTranslations} from "next-intl";
|
||||
import * as Yup from "yup";
|
||||
import {Formik} from "formik";
|
||||
import UserInfo from "../../UserInfo";
|
||||
|
||||
const CreateFormMock = ({Component}) => {
|
||||
const t = useTranslations();
|
||||
const validationSchema = Yup.object().shape({
|
||||
username: Yup.string().required(t("ExpertMangement.error_message_username")),
|
||||
password: Yup.string()
|
||||
.required(t("ExpertMangement.error_message_password"))
|
||||
.matches(
|
||||
/^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
|
||||
t("ExpertMangement.error_message_password_regex")
|
||||
),
|
||||
});
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
username: "",
|
||||
password: "",
|
||||
}}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={(values, {}) => {
|
||||
}}
|
||||
>
|
||||
{formikProps => (<Component formik={formikProps}></Component>)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
describe("UserInfo Component From Expert Management (create)", () => {
|
||||
describe("Rendering", () => {
|
||||
it("UserName TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const usernameTextField = screen.queryByLabelText('نام کاربری');
|
||||
expect(usernameTextField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it("Password TextField Rendered", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
await waitFor(() => {
|
||||
const passwordTextField = screen.queryByLabelText('رمز عبور');
|
||||
expect(passwordTextField).toBeInTheDocument();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
describe("Behavioral", () => {
|
||||
it("Username TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
const usernameTextField = screen.queryByLabelText('نام کاربری');
|
||||
fireEvent.change(usernameTextField, {target: {value: 'exampleUsername'}});
|
||||
await act(() => {
|
||||
expect(usernameTextField).toHaveValue('exampleUsername');
|
||||
})
|
||||
});
|
||||
it("Password TextField Work Correctly", async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
const passwordTextField = screen.queryByLabelText('رمز عبور');
|
||||
fireEvent.change(passwordTextField, {target: {value: 'examplePassword'}});
|
||||
await act(() => {
|
||||
expect(passwordTextField).toHaveValue('examplePassword');
|
||||
})
|
||||
});
|
||||
});
|
||||
describe("validation", () => {
|
||||
it('Should See Error When Username Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
|
||||
const usernameInput = screen.queryByLabelText('نام کاربری');
|
||||
|
||||
fireEvent.change(usernameInput, {target: {value: ''}});
|
||||
fireEvent.blur(usernameInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("نام کاربری خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When Password Input Is Empty', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
|
||||
const passwordInput = screen.queryByLabelText('رمز عبور');
|
||||
|
||||
fireEvent.change(passwordInput, {target: {value: ''}});
|
||||
fireEvent.blur(passwordInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور خود را وارد کنید")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
it('Should See Error When Password Field Is Not On Correct Format', async () => {
|
||||
render(<MockAppWithProviders><CreateFormMock Component={UserInfo}/></MockAppWithProviders>);
|
||||
|
||||
const passwordInput = screen.queryByLabelText('رمز عبور');
|
||||
|
||||
// check without text or symbol
|
||||
fireEvent.change(passwordInput, {target: {value: '12345678'}});
|
||||
fireEvent.blur(passwordInput);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
|
||||
});
|
||||
|
||||
// check without number
|
||||
fireEvent.change(passwordInput, {target: {value: 'abcdefgh'}});
|
||||
fireEvent.blur(passwordInput);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
|
||||
});
|
||||
|
||||
// check under 8 character
|
||||
fireEvent.change(passwordInput, {target: {value: '11Sa'}});
|
||||
fireEvent.blur(passwordInput);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText("رمز عبور باید حداقل 8 کاراکتر و متشکل از عدد، حرف یا سمبل باشد")).toBeInTheDocument()
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import {Grid, IconButton, InputAdornment, TextField} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {Visibility, VisibilityOff} from "@mui/icons-material";
|
||||
import {useState} from "react";
|
||||
|
||||
const UserInfo = ({formik}) => {
|
||||
const t = useTranslations();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const handleClickShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container justifyContent="space-around" spacing={2} sx={{pb: 2}}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField
|
||||
name="username"
|
||||
label={t("ExpertMangement.text_field_username")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.username}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.username && !!formik.errors.username}
|
||||
helperText={formik.touched.username && formik.errors.username ? formik.errors.username : null}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField
|
||||
name="password"
|
||||
label={t("ExpertMangement.text_field_password")}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
size="small"
|
||||
value={formik.values.password}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.password && !!formik.errors.password}
|
||||
helperText={formik.touched.password && formik.errors.password ? formik.errors.password : null}
|
||||
type={showPassword ? "text" : "password"}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton onClick={handleClickShowPassword}>
|
||||
{showPassword ? <Visibility/> : <VisibilityOff/>}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
sx={{width: "100%"}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default UserInfo
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user