diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 05e5a39..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,485 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = crlf
-indent_size = 4
-indent_style = space
-insert_final_newline = false
-max_line_length = 120
-tab_width = 4
-ij_continuation_indent_size = 4
-ij_formatter_off_tag = @formatter:off
-ij_formatter_on_tag = @formatter:on
-ij_formatter_tags_enabled = true
-ij_smart_tabs = false
-ij_visual_guides = none
-ij_wrap_on_typing = false
-
-[*.css]
-ij_css_align_closing_brace_with_properties = false
-ij_css_blank_lines_around_nested_selector = 1
-ij_css_blank_lines_between_blocks = 1
-ij_css_block_comment_add_space = false
-ij_css_brace_placement = end_of_line
-ij_css_enforce_quotes_on_format = false
-ij_css_hex_color_long_format = false
-ij_css_hex_color_lower_case = false
-ij_css_hex_color_short_format = false
-ij_css_hex_color_upper_case = false
-ij_css_keep_blank_lines_in_code = 2
-ij_css_keep_indents_on_empty_lines = false
-ij_css_keep_single_line_blocks = false
-ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
-ij_css_space_after_colon = true
-ij_css_space_before_opening_brace = true
-ij_css_use_double_quotes = true
-ij_css_value_alignment = do_not_align
-
-[*.sass]
-indent_size = 2
-ij_sass_align_closing_brace_with_properties = false
-ij_sass_blank_lines_around_nested_selector = 1
-ij_sass_blank_lines_between_blocks = 1
-ij_sass_brace_placement = 0
-ij_sass_enforce_quotes_on_format = false
-ij_sass_hex_color_long_format = false
-ij_sass_hex_color_lower_case = false
-ij_sass_hex_color_short_format = false
-ij_sass_hex_color_upper_case = false
-ij_sass_keep_blank_lines_in_code = 2
-ij_sass_keep_indents_on_empty_lines = false
-ij_sass_keep_single_line_blocks = false
-ij_sass_line_comment_add_space = false
-ij_sass_line_comment_at_first_column = false
-ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
-ij_sass_space_after_colon = true
-ij_sass_space_before_opening_brace = true
-ij_sass_use_double_quotes = true
-ij_sass_value_alignment = 0
-
-[*.scss]
-indent_size = 2
-ij_scss_align_closing_brace_with_properties = false
-ij_scss_blank_lines_around_nested_selector = 1
-ij_scss_blank_lines_between_blocks = 1
-ij_scss_block_comment_add_space = false
-ij_scss_brace_placement = 0
-ij_scss_enforce_quotes_on_format = false
-ij_scss_hex_color_long_format = false
-ij_scss_hex_color_lower_case = false
-ij_scss_hex_color_short_format = false
-ij_scss_hex_color_upper_case = false
-ij_scss_keep_blank_lines_in_code = 2
-ij_scss_keep_indents_on_empty_lines = false
-ij_scss_keep_single_line_blocks = false
-ij_scss_line_comment_add_space = false
-ij_scss_line_comment_at_first_column = false
-ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
-ij_scss_space_after_colon = true
-ij_scss_space_before_opening_brace = true
-ij_scss_use_double_quotes = true
-ij_scss_value_alignment = 0
-
-[{*.ats,*.cts,*.mts,*.ts}]
-ij_continuation_indent_size = 4
-ij_typescript_align_imports = false
-ij_typescript_align_multiline_array_initializer_expression = false
-ij_typescript_align_multiline_binary_operation = false
-ij_typescript_align_multiline_chained_methods = false
-ij_typescript_align_multiline_extends_list = false
-ij_typescript_align_multiline_for = true
-ij_typescript_align_multiline_parameters = true
-ij_typescript_align_multiline_parameters_in_calls = false
-ij_typescript_align_multiline_ternary_operation = false
-ij_typescript_align_object_properties = 0
-ij_typescript_align_union_types = false
-ij_typescript_align_var_statements = 0
-ij_typescript_array_initializer_new_line_after_left_brace = false
-ij_typescript_array_initializer_right_brace_on_new_line = false
-ij_typescript_array_initializer_wrap = off
-ij_typescript_assignment_wrap = off
-ij_typescript_binary_operation_sign_on_next_line = false
-ij_typescript_binary_operation_wrap = off
-ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
-ij_typescript_blank_lines_after_imports = 1
-ij_typescript_blank_lines_around_class = 1
-ij_typescript_blank_lines_around_field = 0
-ij_typescript_blank_lines_around_field_in_interface = 0
-ij_typescript_blank_lines_around_function = 1
-ij_typescript_blank_lines_around_method = 1
-ij_typescript_blank_lines_around_method_in_interface = 1
-ij_typescript_block_brace_style = end_of_line
-ij_typescript_block_comment_add_space = false
-ij_typescript_block_comment_at_first_column = true
-ij_typescript_call_parameters_new_line_after_left_paren = false
-ij_typescript_call_parameters_right_paren_on_new_line = false
-ij_typescript_call_parameters_wrap = off
-ij_typescript_catch_on_new_line = false
-ij_typescript_chained_call_dot_on_new_line = true
-ij_typescript_class_brace_style = end_of_line
-ij_typescript_comma_on_new_line = false
-ij_typescript_do_while_brace_force = never
-ij_typescript_else_on_new_line = false
-ij_typescript_enforce_trailing_comma = keep
-ij_typescript_enum_constants_wrap = on_every_item
-ij_typescript_extends_keyword_wrap = off
-ij_typescript_extends_list_wrap = off
-ij_typescript_field_prefix = _
-ij_typescript_file_name_style = relaxed
-ij_typescript_finally_on_new_line = false
-ij_typescript_for_brace_force = never
-ij_typescript_for_statement_new_line_after_left_paren = false
-ij_typescript_for_statement_right_paren_on_new_line = false
-ij_typescript_for_statement_wrap = off
-ij_typescript_force_quote_style = false
-ij_typescript_force_semicolon_style = false
-ij_typescript_function_expression_brace_style = end_of_line
-ij_typescript_if_brace_force = never
-ij_typescript_import_merge_members = global
-ij_typescript_import_prefer_absolute_path = global
-ij_typescript_import_sort_members = true
-ij_typescript_import_sort_module_name = false
-ij_typescript_import_use_node_resolution = true
-ij_typescript_imports_wrap = on_every_item
-ij_typescript_indent_case_from_switch = true
-ij_typescript_indent_chained_calls = true
-ij_typescript_indent_package_children = 0
-ij_typescript_jsdoc_include_types = false
-ij_typescript_jsx_attribute_value = braces
-ij_typescript_keep_blank_lines_in_code = 2
-ij_typescript_keep_first_column_comment = true
-ij_typescript_keep_indents_on_empty_lines = false
-ij_typescript_keep_line_breaks = true
-ij_typescript_keep_simple_blocks_in_one_line = false
-ij_typescript_keep_simple_methods_in_one_line = false
-ij_typescript_line_comment_add_space = true
-ij_typescript_line_comment_at_first_column = false
-ij_typescript_method_brace_style = end_of_line
-ij_typescript_method_call_chain_wrap = off
-ij_typescript_method_parameters_new_line_after_left_paren = false
-ij_typescript_method_parameters_right_paren_on_new_line = false
-ij_typescript_method_parameters_wrap = off
-ij_typescript_object_literal_wrap = on_every_item
-ij_typescript_object_types_wrap = on_every_item
-ij_typescript_parentheses_expression_new_line_after_left_paren = false
-ij_typescript_parentheses_expression_right_paren_on_new_line = false
-ij_typescript_place_assignment_sign_on_next_line = false
-ij_typescript_prefer_as_type_cast = false
-ij_typescript_prefer_explicit_types_function_expression_returns = false
-ij_typescript_prefer_explicit_types_function_returns = false
-ij_typescript_prefer_explicit_types_vars_fields = false
-ij_typescript_prefer_parameters_wrap = false
-ij_typescript_reformat_c_style_comments = false
-ij_typescript_space_after_colon = true
-ij_typescript_space_after_comma = true
-ij_typescript_space_after_dots_in_rest_parameter = false
-ij_typescript_space_after_generator_mult = true
-ij_typescript_space_after_property_colon = true
-ij_typescript_space_after_quest = true
-ij_typescript_space_after_type_colon = true
-ij_typescript_space_after_unary_not = false
-ij_typescript_space_before_async_arrow_lparen = true
-ij_typescript_space_before_catch_keyword = true
-ij_typescript_space_before_catch_left_brace = true
-ij_typescript_space_before_catch_parentheses = true
-ij_typescript_space_before_class_lbrace = true
-ij_typescript_space_before_class_left_brace = true
-ij_typescript_space_before_colon = true
-ij_typescript_space_before_comma = false
-ij_typescript_space_before_do_left_brace = true
-ij_typescript_space_before_else_keyword = true
-ij_typescript_space_before_else_left_brace = true
-ij_typescript_space_before_finally_keyword = true
-ij_typescript_space_before_finally_left_brace = true
-ij_typescript_space_before_for_left_brace = true
-ij_typescript_space_before_for_parentheses = true
-ij_typescript_space_before_for_semicolon = false
-ij_typescript_space_before_function_left_parenth = true
-ij_typescript_space_before_generator_mult = false
-ij_typescript_space_before_if_left_brace = true
-ij_typescript_space_before_if_parentheses = true
-ij_typescript_space_before_method_call_parentheses = false
-ij_typescript_space_before_method_left_brace = true
-ij_typescript_space_before_method_parentheses = false
-ij_typescript_space_before_property_colon = false
-ij_typescript_space_before_quest = true
-ij_typescript_space_before_switch_left_brace = true
-ij_typescript_space_before_switch_parentheses = true
-ij_typescript_space_before_try_left_brace = true
-ij_typescript_space_before_type_colon = false
-ij_typescript_space_before_unary_not = false
-ij_typescript_space_before_while_keyword = true
-ij_typescript_space_before_while_left_brace = true
-ij_typescript_space_before_while_parentheses = true
-ij_typescript_spaces_around_additive_operators = true
-ij_typescript_spaces_around_arrow_function_operator = true
-ij_typescript_spaces_around_assignment_operators = true
-ij_typescript_spaces_around_bitwise_operators = true
-ij_typescript_spaces_around_equality_operators = true
-ij_typescript_spaces_around_logical_operators = true
-ij_typescript_spaces_around_multiplicative_operators = true
-ij_typescript_spaces_around_relational_operators = true
-ij_typescript_spaces_around_shift_operators = true
-ij_typescript_spaces_around_unary_operator = false
-ij_typescript_spaces_within_array_initializer_brackets = false
-ij_typescript_spaces_within_brackets = false
-ij_typescript_spaces_within_catch_parentheses = false
-ij_typescript_spaces_within_for_parentheses = false
-ij_typescript_spaces_within_if_parentheses = false
-ij_typescript_spaces_within_imports = false
-ij_typescript_spaces_within_interpolation_expressions = false
-ij_typescript_spaces_within_method_call_parentheses = false
-ij_typescript_spaces_within_method_parentheses = false
-ij_typescript_spaces_within_object_literal_braces = false
-ij_typescript_spaces_within_object_type_braces = true
-ij_typescript_spaces_within_parentheses = false
-ij_typescript_spaces_within_switch_parentheses = false
-ij_typescript_spaces_within_type_assertion = false
-ij_typescript_spaces_within_union_types = true
-ij_typescript_spaces_within_while_parentheses = false
-ij_typescript_special_else_if_treatment = true
-ij_typescript_ternary_operation_signs_on_next_line = false
-ij_typescript_ternary_operation_wrap = off
-ij_typescript_union_types_wrap = on_every_item
-ij_typescript_use_chained_calls_group_indents = false
-ij_typescript_use_double_quotes = true
-ij_typescript_use_explicit_js_extension = auto
-ij_typescript_use_path_mapping = always
-ij_typescript_use_public_modifier = false
-ij_typescript_use_semicolon_after_statement = true
-ij_typescript_var_declaration_wrap = normal
-ij_typescript_while_brace_force = never
-ij_typescript_while_on_new_line = false
-ij_typescript_wrap_comments = false
-
-[{*.cjs,*.js}]
-ij_continuation_indent_size = 4
-ij_javascript_align_imports = false
-ij_javascript_align_multiline_array_initializer_expression = false
-ij_javascript_align_multiline_binary_operation = false
-ij_javascript_align_multiline_chained_methods = false
-ij_javascript_align_multiline_extends_list = false
-ij_javascript_align_multiline_for = true
-ij_javascript_align_multiline_parameters = true
-ij_javascript_align_multiline_parameters_in_calls = false
-ij_javascript_align_multiline_ternary_operation = false
-ij_javascript_align_object_properties = 0
-ij_javascript_align_union_types = false
-ij_javascript_align_var_statements = 0
-ij_javascript_array_initializer_new_line_after_left_brace = false
-ij_javascript_array_initializer_right_brace_on_new_line = false
-ij_javascript_array_initializer_wrap = off
-ij_javascript_assignment_wrap = off
-ij_javascript_binary_operation_sign_on_next_line = false
-ij_javascript_binary_operation_wrap = off
-ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
-ij_javascript_blank_lines_after_imports = 1
-ij_javascript_blank_lines_around_class = 1
-ij_javascript_blank_lines_around_field = 0
-ij_javascript_blank_lines_around_function = 1
-ij_javascript_blank_lines_around_method = 1
-ij_javascript_block_brace_style = end_of_line
-ij_javascript_block_comment_add_space = false
-ij_javascript_block_comment_at_first_column = true
-ij_javascript_call_parameters_new_line_after_left_paren = false
-ij_javascript_call_parameters_right_paren_on_new_line = false
-ij_javascript_call_parameters_wrap = off
-ij_javascript_catch_on_new_line = false
-ij_javascript_chained_call_dot_on_new_line = true
-ij_javascript_class_brace_style = end_of_line
-ij_javascript_comma_on_new_line = false
-ij_javascript_do_while_brace_force = never
-ij_javascript_else_on_new_line = false
-ij_javascript_enforce_trailing_comma = keep
-ij_javascript_extends_keyword_wrap = off
-ij_javascript_extends_list_wrap = off
-ij_javascript_field_prefix = _
-ij_javascript_file_name_style = relaxed
-ij_javascript_finally_on_new_line = false
-ij_javascript_for_brace_force = never
-ij_javascript_for_statement_new_line_after_left_paren = false
-ij_javascript_for_statement_right_paren_on_new_line = false
-ij_javascript_for_statement_wrap = off
-ij_javascript_force_quote_style = false
-ij_javascript_force_semicolon_style = false
-ij_javascript_function_expression_brace_style = end_of_line
-ij_javascript_if_brace_force = never
-ij_javascript_import_merge_members = global
-ij_javascript_import_prefer_absolute_path = global
-ij_javascript_import_sort_members = true
-ij_javascript_import_sort_module_name = false
-ij_javascript_import_use_node_resolution = true
-ij_javascript_imports_wrap = on_every_item
-ij_javascript_indent_case_from_switch = true
-ij_javascript_indent_chained_calls = true
-ij_javascript_indent_package_children = 0
-ij_javascript_jsx_attribute_value = braces
-ij_javascript_keep_blank_lines_in_code = 2
-ij_javascript_keep_first_column_comment = true
-ij_javascript_keep_indents_on_empty_lines = false
-ij_javascript_keep_line_breaks = true
-ij_javascript_keep_simple_blocks_in_one_line = false
-ij_javascript_keep_simple_methods_in_one_line = false
-ij_javascript_line_comment_add_space = true
-ij_javascript_line_comment_at_first_column = false
-ij_javascript_method_brace_style = end_of_line
-ij_javascript_method_call_chain_wrap = off
-ij_javascript_method_parameters_new_line_after_left_paren = false
-ij_javascript_method_parameters_right_paren_on_new_line = false
-ij_javascript_method_parameters_wrap = off
-ij_javascript_object_literal_wrap = on_every_item
-ij_javascript_object_types_wrap = on_every_item
-ij_javascript_parentheses_expression_new_line_after_left_paren = false
-ij_javascript_parentheses_expression_right_paren_on_new_line = false
-ij_javascript_place_assignment_sign_on_next_line = false
-ij_javascript_prefer_as_type_cast = false
-ij_javascript_prefer_explicit_types_function_expression_returns = false
-ij_javascript_prefer_explicit_types_function_returns = false
-ij_javascript_prefer_explicit_types_vars_fields = false
-ij_javascript_prefer_parameters_wrap = false
-ij_javascript_reformat_c_style_comments = false
-ij_javascript_space_after_colon = true
-ij_javascript_space_after_comma = true
-ij_javascript_space_after_dots_in_rest_parameter = false
-ij_javascript_space_after_generator_mult = true
-ij_javascript_space_after_property_colon = true
-ij_javascript_space_after_quest = true
-ij_javascript_space_after_type_colon = true
-ij_javascript_space_after_unary_not = false
-ij_javascript_space_before_async_arrow_lparen = true
-ij_javascript_space_before_catch_keyword = true
-ij_javascript_space_before_catch_left_brace = true
-ij_javascript_space_before_catch_parentheses = true
-ij_javascript_space_before_class_lbrace = true
-ij_javascript_space_before_class_left_brace = true
-ij_javascript_space_before_colon = true
-ij_javascript_space_before_comma = false
-ij_javascript_space_before_do_left_brace = true
-ij_javascript_space_before_else_keyword = true
-ij_javascript_space_before_else_left_brace = true
-ij_javascript_space_before_finally_keyword = true
-ij_javascript_space_before_finally_left_brace = true
-ij_javascript_space_before_for_left_brace = true
-ij_javascript_space_before_for_parentheses = true
-ij_javascript_space_before_for_semicolon = false
-ij_javascript_space_before_function_left_parenth = true
-ij_javascript_space_before_generator_mult = false
-ij_javascript_space_before_if_left_brace = true
-ij_javascript_space_before_if_parentheses = true
-ij_javascript_space_before_method_call_parentheses = false
-ij_javascript_space_before_method_left_brace = true
-ij_javascript_space_before_method_parentheses = false
-ij_javascript_space_before_property_colon = false
-ij_javascript_space_before_quest = true
-ij_javascript_space_before_switch_left_brace = true
-ij_javascript_space_before_switch_parentheses = true
-ij_javascript_space_before_try_left_brace = true
-ij_javascript_space_before_type_colon = false
-ij_javascript_space_before_unary_not = false
-ij_javascript_space_before_while_keyword = true
-ij_javascript_space_before_while_left_brace = true
-ij_javascript_space_before_while_parentheses = true
-ij_javascript_spaces_around_additive_operators = true
-ij_javascript_spaces_around_arrow_function_operator = true
-ij_javascript_spaces_around_assignment_operators = true
-ij_javascript_spaces_around_bitwise_operators = true
-ij_javascript_spaces_around_equality_operators = true
-ij_javascript_spaces_around_logical_operators = true
-ij_javascript_spaces_around_multiplicative_operators = true
-ij_javascript_spaces_around_relational_operators = true
-ij_javascript_spaces_around_shift_operators = true
-ij_javascript_spaces_around_unary_operator = false
-ij_javascript_spaces_within_array_initializer_brackets = false
-ij_javascript_spaces_within_brackets = false
-ij_javascript_spaces_within_catch_parentheses = false
-ij_javascript_spaces_within_for_parentheses = false
-ij_javascript_spaces_within_if_parentheses = false
-ij_javascript_spaces_within_imports = false
-ij_javascript_spaces_within_interpolation_expressions = false
-ij_javascript_spaces_within_method_call_parentheses = false
-ij_javascript_spaces_within_method_parentheses = false
-ij_javascript_spaces_within_object_literal_braces = false
-ij_javascript_spaces_within_object_type_braces = true
-ij_javascript_spaces_within_parentheses = false
-ij_javascript_spaces_within_switch_parentheses = false
-ij_javascript_spaces_within_type_assertion = false
-ij_javascript_spaces_within_union_types = true
-ij_javascript_spaces_within_while_parentheses = false
-ij_javascript_special_else_if_treatment = true
-ij_javascript_ternary_operation_signs_on_next_line = false
-ij_javascript_ternary_operation_wrap = off
-ij_javascript_union_types_wrap = on_every_item
-ij_javascript_use_chained_calls_group_indents = false
-ij_javascript_use_double_quotes = true
-ij_javascript_use_explicit_js_extension = auto
-ij_javascript_use_path_mapping = always
-ij_javascript_use_public_modifier = false
-ij_javascript_use_semicolon_after_statement = true
-ij_javascript_var_declaration_wrap = normal
-ij_javascript_while_brace_force = never
-ij_javascript_while_on_new_line = false
-ij_javascript_wrap_comments = false
-
-[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
-indent_size = 2
-ij_json_array_wrapping = split_into_lines
-ij_json_keep_blank_lines_in_code = 0
-ij_json_keep_indents_on_empty_lines = false
-ij_json_keep_line_breaks = true
-ij_json_keep_trailing_comma = false
-ij_json_object_wrapping = split_into_lines
-ij_json_property_alignment = do_not_align
-ij_json_space_after_colon = true
-ij_json_space_after_comma = true
-ij_json_space_before_colon = false
-ij_json_space_before_comma = false
-ij_json_spaces_within_braces = false
-ij_json_spaces_within_brackets = false
-ij_json_wrap_long_lines = false
-
-[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}]
-ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
-ij_html_align_attributes = true
-ij_html_align_text = false
-ij_html_attribute_wrap = normal
-ij_html_block_comment_add_space = false
-ij_html_block_comment_at_first_column = true
-ij_html_do_not_align_children_of_min_lines = 0
-ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
-ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
-ij_html_enforce_quotes = false
-ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
-ij_html_keep_blank_lines = 2
-ij_html_keep_indents_on_empty_lines = false
-ij_html_keep_line_breaks = true
-ij_html_keep_line_breaks_in_text = true
-ij_html_keep_whitespaces = false
-ij_html_keep_whitespaces_inside = span, pre, textarea
-ij_html_line_comment_at_first_column = true
-ij_html_new_line_after_last_attribute = never
-ij_html_new_line_before_first_attribute = never
-ij_html_quote_style = double
-ij_html_remove_new_line_before_tags = br
-ij_html_space_after_tag_name = false
-ij_html_space_around_equality_in_attribute = false
-ij_html_space_inside_empty_tag = false
-ij_html_text_wrap = normal
-
-[{*.markdown,*.md}]
-ij_markdown_force_one_space_after_blockquote_symbol = true
-ij_markdown_force_one_space_after_header_symbol = true
-ij_markdown_force_one_space_after_list_bullet = true
-ij_markdown_force_one_space_between_words = true
-ij_markdown_format_tables = true
-ij_markdown_insert_quote_arrows_on_wrap = true
-ij_markdown_keep_indents_on_empty_lines = false
-ij_markdown_keep_line_breaks_inside_text_blocks = true
-ij_markdown_max_lines_around_block_elements = 1
-ij_markdown_max_lines_around_header = 1
-ij_markdown_max_lines_between_paragraphs = 1
-ij_markdown_min_lines_around_block_elements = 1
-ij_markdown_min_lines_around_header = 1
-ij_markdown_min_lines_between_paragraphs = 1
-ij_markdown_wrap_text_if_long = true
-ij_markdown_wrap_text_inside_blockquotes = true
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index cb6d4e4..0000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extends": [
- "next/core-web-vitals"
- ]
-}
diff --git a/.gitignore b/.gitignore
index 1e62a6d..5ef6a52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,34 +1,41 @@
-# Logs
-logs
-*.log
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-# Runtime data
-pids
-*.pid
-*.seed
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
+# testing
+/coverage
-# Coverage directory used by tools like istanbul
-coverage
+# next.js
+/.next/
+/out/
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
+# production
+/build
-# node-waf configuration
-.lock-wscript
+# misc
+.DS_Store
+*.pem
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
-# Dependency directory
-node_modules
-cypress/videos
-cypress/screenshots
-.next
+# env files (can opt-in for committing if needed)
.env*
-.env
-.idea
-package-lock.json
-ecosystem.config.js
\ No newline at end of file
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index a4cba6c..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-image: node:latest
-
-cache:
- paths:
- - node_modules
-
-stages:
- - lint
- - test
- - test:build
- - deploy
-
-merge:test:lint:
- stage: lint
- script:
- - npm install
- - cp example.env.local .env.local
- - cp example.env.local .env.test
- - npm run lint
- only:
- - merge_requests
-
-merge:test:jest:
- stage: test
- script:
- - npm install
- - cp example.env.local .env.local
- - cp example.env.local .env.test
- - npm run test
- only:
- - merge_requests
-
-#merge:test:build:
-# stage: test:build
-# script:
-# - npm install
-# - cp example.env.local .env.local
-# - cp example.env.local .env.test
-# - npm run build
-# only:
-# - merge_requests
-
-test:lint:
- stage: lint
- script:
- - npm install
- - cp example.env.local .env.local
- - cp example.env.local .env.test
- - npm run lint
- only:
- - develop
- - main
-
-test:jest:
- stage: test
- script:
- - npm install
- - cp example.env.local .env.local
- - cp example.env.local .env.test
- - npm run test
- only:
- - develop
- - main
-
-#test:build:
-# stage: test:build
-# script:
-# - npm install
-# - cp example.env.local .env.local
-# - cp example.env.local .env.test
-# - npm run build
-# only:
-# - develop
-# - main
-
-deploy:
- stage: deploy
- script:
- - echo "Run deploy project"
- only:
- - main
\ No newline at end of file
diff --git a/README.md b/README.md
index 8d1c8b6..09a8a4d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,36 @@
-
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/cypress.config.js b/cypress.config.js
deleted file mode 100644
index 3b67130..0000000
--- a/cypress.config.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { defineConfig } = require("cypress");
-
-module.exports = defineConfig({
- e2e: {
- setupNodeEvents(on, config) {
- // implement node event listeners here
- },
- },
-
- component: {
- devServer: {
- framework: "next",
- bundler: "webpack",
- },
- },
-});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
deleted file mode 100644
index 66ea16e..0000000
--- a/cypress/support/commands.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// ***********************************************
-// 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) => { ... })
\ No newline at end of file
diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html
deleted file mode 100644
index 3e16e9b..0000000
--- a/cypress/support/component-index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
- Components App
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cypress/support/component.js b/cypress/support/component.js
deleted file mode 100644
index 8f9154b..0000000
--- a/cypress/support/component.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// ***********************************************************
-// 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()
\ No newline at end of file
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
deleted file mode 100644
index 0e7290a..0000000
--- a/cypress/support/e2e.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// ***********************************************************
-// 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')
\ No newline at end of file
diff --git a/ecosystem.config.js.example b/ecosystem.config.js.example
deleted file mode 100644
index 6847796..0000000
--- a/ecosystem.config.js.example
+++ /dev/null
@@ -1,18 +0,0 @@
-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
- }
- }],
-};
\ No newline at end of file
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..348c45a
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,14 @@
+import { dirname } from "path";
+import { fileURLToPath } from "url";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+});
+
+const eslintConfig = [...compat.extends("next/core-web-vitals")];
+
+export default eslintConfig;
diff --git a/example.env.local b/example.env.local
index ddb10b8..7a4dbd6 100644
--- a/example.env.local
+++ b/example.env.local
@@ -1,17 +1,5 @@
-NEXT_PUBLIC_API_NAME = "CRM Dashboard"
-NEXT_PUBLIC_API_VERSION = "1.21.10"
-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"
+NEXT_PUBLIC_VERSION = "2.0.0"
+NEXT_PUBLIC_API_URL = "https://crm.witel.ir/server"
+NEXT_PUBLIC_SERVER_SOCKET_URL = "wss://crm.witel.ir"
+NEXT_PUBLIC_POWERED_BY_URL = "https://witel.ir"
\ No newline at end of file
diff --git a/jest.config.mjs b/jest.config.mjs
deleted file mode 100644
index 5bda02f..0000000
--- a/jest.config.mjs
+++ /dev/null
@@ -1,17 +0,0 @@
-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: ['/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)
\ No newline at end of file
diff --git a/jest.setup.js b/jest.setup.js
deleted file mode 100644
index fadd766..0000000
--- a/jest.setup.js
+++ /dev/null
@@ -1,23 +0,0 @@
-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()
-})
-
diff --git a/jsconfig.json b/jsconfig.json
index fcd02aa..b8d6842 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -1,12 +1,7 @@
{
"compilerOptions": {
"paths": {
- "@/*": [
- "./src/*"
- ],
- "&/*": [
- "./public/*"
- ]
+ "@/*": ["./src/*"]
}
}
}
diff --git a/mocks/AppWithProvider.jsx b/mocks/AppWithProvider.jsx
deleted file mode 100644
index a81bb3c..0000000
--- a/mocks/AppWithProvider.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-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 ( (<>{children}>)} pageProps={pageProps}/>)
-}
-
-export default MockAppWithProviders
\ No newline at end of file
diff --git a/mocks/handler.js b/mocks/handler.js
deleted file mode 100644
index 232c91e..0000000
--- a/mocks/handler.js
+++ /dev/null
@@ -1,15 +0,0 @@
-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,
-];
diff --git a/mocks/handlers/categories.js b/mocks/handlers/categories.js
deleted file mode 100644
index 6864331..0000000
--- a/mocks/handlers/categories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-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: "مزاحم",
- },
- ],
- })
- );
- }),
-];
diff --git a/mocks/handlers/experts.js b/mocks/handlers/experts.js
deleted file mode 100644
index 1bf2a31..0000000
--- a/mocks/handlers/experts.js
+++ /dev/null
@@ -1,20 +0,0 @@
-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),
- );
- }),
-]
\ No newline at end of file
diff --git a/mocks/handlers/permissions.js b/mocks/handlers/permissions.js
deleted file mode 100644
index dfe792b..0000000
--- a/mocks/handlers/permissions.js
+++ /dev/null
@@ -1,23 +0,0 @@
-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: "مدیریت کارتابل کارگروه استانی"
- }
- ]
- }
- ))
- })
-]
\ No newline at end of file
diff --git a/mocks/handlers/provinces.js b/mocks/handlers/provinces.js
deleted file mode 100644
index 9065c12..0000000
--- a/mocks/handlers/provinces.js
+++ /dev/null
@@ -1,19 +0,0 @@
-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: "اردبیل"
- }
- ]
- }))
- }),
-]
\ No newline at end of file
diff --git a/mocks/handlers/roles.js b/mocks/handlers/roles.js
deleted file mode 100644
index 1c26ef5..0000000
--- a/mocks/handlers/roles.js
+++ /dev/null
@@ -1,70 +0,0 @@
-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: "مدیر"
- }
- ]
- }))
- }),
-]
\ No newline at end of file
diff --git a/mocks/handlers/user.js b/mocks/handlers/user.js
deleted file mode 100644
index 7e84703..0000000
--- a/mocks/handlers/user.js
+++ /dev/null
@@ -1,29 +0,0 @@
-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),
- );
- }),
-]
\ No newline at end of file
diff --git a/mocks/server.js b/mocks/server.js
deleted file mode 100644
index 0bf9e08..0000000
--- a/mocks/server.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import {setupServer} from "msw/node";
-import {handler} from "./handler";
-
-export const server = setupServer(...handler)
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
deleted file mode 100644
index a288e34..0000000
--- a/next.config.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @type {import('next').NextConfig} */
-
-const nextConfig = {
- reactStrictMode: true,
- i18n: {
- defaultLocale: 'fa',
- locales: ['fa'],
- localeDetection: false,
- }
-}
-
-module.exports = nextConfig
diff --git a/next.config.mjs b/next.config.mjs
new file mode 100644
index 0000000..4678774
--- /dev/null
+++ b/next.config.mjs
@@ -0,0 +1,4 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {};
+
+export default nextConfig;
diff --git a/package.json b/package.json
index f82c9f2..5551615 100644
--- a/package.json
+++ b/package.json
@@ -1,70 +1,41 @@
{
- "name": "dashboard",
+ "name": "app",
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "next dev",
+ "dev": "next dev --turbopack",
"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"
+ "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\""
},
"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",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.0",
+ "@hookform/resolvers": "^5.0.1",
+ "@mui/icons-material": "^7.0.2",
+ "@mui/material": "^7.0.2",
+ "@mui/material-nextjs": "^7.0.2",
+ "axios": "^1.9.0",
"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",
+ "lz-string": "^1.5.0",
+ "next": "15.3.1",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-hook-form": "^7.56.1",
+ "react-toastify": "^11.0.5",
+ "socket.io-client": "^4.8.1",
+ "stylis": "^4.3.6",
"stylis-plugin-rtl": "^2.1.1",
- "swr": "^2.1.5",
- "yup": "^1.1.1"
+ "swr": "^2.3.3",
+ "yup": "^1.6.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"
+ "@eslint/eslintrc": "^3",
+ "eslint": "^9",
+ "eslint-config-next": "15.3.1",
+ "prettier": "3.5.3",
+ "sass": "^1.87.0"
}
-}
+}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..5900a63
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,5206 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@emotion/cache':
+ specifier: ^11.14.0
+ version: 11.14.0
+ '@emotion/react':
+ specifier: ^11.14.0
+ version: 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ '@emotion/styled':
+ specifier: ^11.14.0
+ version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+ '@hookform/resolvers':
+ specifier: ^5.0.1
+ version: 5.0.1(react-hook-form@7.56.2(react@19.1.0))
+ '@mui/icons-material':
+ specifier: ^7.0.2
+ version: 7.0.2(@mui/material@7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+ '@mui/material':
+ specifier: ^7.0.2
+ version: 7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@mui/material-nextjs':
+ specifier: ^7.0.2
+ version: 7.0.2(@emotion/cache@11.14.0)(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.87.0))(react@19.1.0)
+ axios:
+ specifier: ^1.9.0
+ version: 1.9.0
+ jalali-moment:
+ specifier: ^3.3.11
+ version: 3.3.11
+ lz-string:
+ specifier: ^1.5.0
+ version: 1.5.0
+ next:
+ specifier: 15.3.1
+ version: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.87.0)
+ react:
+ specifier: ^19.0.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.0.0
+ version: 19.1.0(react@19.1.0)
+ react-hook-form:
+ specifier: ^7.56.1
+ version: 7.56.2(react@19.1.0)
+ react-toastify:
+ specifier: ^11.0.5
+ version: 11.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ socket.io-client:
+ specifier: ^4.8.1
+ version: 4.8.1
+ stylis:
+ specifier: ^4.3.6
+ version: 4.3.6
+ stylis-plugin-rtl:
+ specifier: ^2.1.1
+ version: 2.1.1(stylis@4.3.6)
+ swr:
+ specifier: ^2.3.3
+ version: 2.3.3(react@19.1.0)
+ yup:
+ specifier: ^1.6.1
+ version: 1.6.1
+ devDependencies:
+ '@eslint/eslintrc':
+ specifier: ^3
+ version: 3.3.1
+ eslint:
+ specifier: ^9
+ version: 9.26.0
+ eslint-config-next:
+ specifier: 15.3.1
+ version: 15.3.1(eslint@9.26.0)(typescript@5.8.3)
+ prettier:
+ specifier: 3.5.3
+ version: 3.5.3
+ sass:
+ specifier: ^1.87.0
+ version: 1.87.0
+
+packages:
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.27.1':
+ resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.27.1':
+ resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/runtime@7.27.1':
+ resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.27.1':
+ resolution: {integrity: sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.27.1':
+ resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.27.1':
+ resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@emnapi/core@1.4.3':
+ resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
+
+ '@emnapi/runtime@1.4.3':
+ resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
+
+ '@emnapi/wasi-threads@1.0.2':
+ resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==}
+
+ '@emotion/babel-plugin@11.13.5':
+ resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
+
+ '@emotion/cache@11.14.0':
+ resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
+
+ '@emotion/hash@0.9.2':
+ resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
+
+ '@emotion/is-prop-valid@1.3.1':
+ resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
+ '@emotion/react@11.14.0':
+ resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/serialize@1.3.3':
+ resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
+
+ '@emotion/sheet@1.4.0':
+ resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
+
+ '@emotion/styled@11.14.0':
+ resolution: {integrity: sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==}
+ peerDependencies:
+ '@emotion/react': ^11.0.0-rc.0
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/unitless@0.10.0':
+ resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0':
+ resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@emotion/utils@1.4.2':
+ resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
+
+ '@emotion/weak-memoize@0.4.0':
+ resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
+
+ '@eslint-community/eslint-utils@4.7.0':
+ resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.1':
+ resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.20.0':
+ resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-helpers@0.2.2':
+ resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.13.0':
+ resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.1':
+ resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.26.0':
+ resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.6':
+ resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.2.8':
+ resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@hookform/resolvers@5.0.1':
+ resolution: {integrity: sha512-u/+Jp83luQNx9AdyW2fIPGY6Y7NG68eN2ZW8FOJYL+M0i4s49+refdJdOp/A9n9HFQtQs3HIDHQvX3ZET2o7YA==}
+ peerDependencies:
+ react-hook-form: ^7.55.0
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanfs/node@0.16.6':
+ resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.3.1':
+ resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
+ engines: {node: '>=18.18'}
+
+ '@humanwhocodes/retry@0.4.2':
+ resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
+ engines: {node: '>=18.18'}
+
+ '@img/sharp-darwin-arm64@0.34.1':
+ resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.34.1':
+ resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.1.0':
+ resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.1.0':
+ resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.1.0':
+ resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-arm@1.1.0':
+ resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-ppc64@1.1.0':
+ resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-s390x@1.1.0':
+ resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-x64@1.1.0':
+ resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
+ resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.1.0':
+ resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linux-arm64@0.34.1':
+ resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linux-arm@0.34.1':
+ resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-linux-s390x@0.34.1':
+ resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-linux-x64@0.34.1':
+ resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-arm64@0.34.1':
+ resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-x64@0.34.1':
+ resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-wasm32@0.34.1':
+ resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-ia32@0.34.1':
+ resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.34.1':
+ resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.8':
+ resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+ '@modelcontextprotocol/sdk@1.11.0':
+ resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==}
+ engines: {node: '>=18'}
+
+ '@mui/core-downloads-tracker@7.0.2':
+ resolution: {integrity: sha512-TfeFU9TgN1N06hyb/pV/63FfO34nijZRMqgHk0TJ3gkl4Fbd+wZ73+ZtOd7jag6hMmzO9HSrBc6Vdn591nhkAg==}
+
+ '@mui/icons-material@7.0.2':
+ resolution: {integrity: sha512-Bo57PFLOqXOqPNrXjd8AhzH5s6TCsNUQbvnQ0VKZ8D+lIlteqKnrk/O1luMJUc/BXONK7BfIdTdc7qOnXYbMdw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@mui/material': ^7.0.2
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/material-nextjs@7.0.2':
+ resolution: {integrity: sha512-hjm0MFSjx7HWbORMRldbwfKrQPHTSMXD6dkCCSTQZ2XX8fkKlnOXNnoXUFzlzFtMKMzs9QOfe3dHooTvnDEfuQ==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/cache': ^11.11.0
+ '@emotion/react': ^11.11.4
+ '@emotion/server': ^11.11.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ next: ^13.0.0 || ^14.0.0 || ^15.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/cache':
+ optional: true
+ '@emotion/server':
+ optional: true
+ '@types/react':
+ optional: true
+
+ '@mui/material@7.0.2':
+ resolution: {integrity: sha512-rjJlJ13+3LdLfobRplkXbjIFEIkn6LgpetgU/Cs3Xd8qINCCQK9qXQIjjQ6P0FXFTPFzEVMj0VgBR1mN+FhOcA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@mui/material-pigment-css': ^7.0.2
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@mui/material-pigment-css':
+ optional: true
+ '@types/react':
+ optional: true
+
+ '@mui/private-theming@7.0.2':
+ resolution: {integrity: sha512-6lt8heDC9wN8YaRqEdhqnm0cFCv08AMf4IlttFvOVn7ZdKd81PNpD/rEtPGLLwQAFyyKSxBG4/2XCgpbcdNKiA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/styled-engine@7.0.2':
+ resolution: {integrity: sha512-11Bt4YdHGlh7sB8P75S9mRCUxTlgv7HGbr0UKz6m6Z9KLeiw1Bm9y/t3iqLLVMvSHYB6zL8X8X+LmfTE++gyBw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.4.1
+ '@emotion/styled': ^11.3.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+
+ '@mui/system@7.0.2':
+ resolution: {integrity: sha512-yFUraAWYWuKIISPPEVPSQ1NLeqmTT4qiQ+ktmyS8LO/KwHxB+NNVOacEZaIofh5x1NxY8rzphvU5X2heRZ/RDA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@types/react':
+ optional: true
+
+ '@mui/types@7.4.1':
+ resolution: {integrity: sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/utils@7.0.2':
+ resolution: {integrity: sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@napi-rs/wasm-runtime@0.2.9':
+ resolution: {integrity: sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==}
+
+ '@next/env@15.3.1':
+ resolution: {integrity: sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ==}
+
+ '@next/eslint-plugin-next@15.3.1':
+ resolution: {integrity: sha512-oEs4dsfM6iyER3jTzMm4kDSbrQJq8wZw5fmT6fg2V3SMo+kgG+cShzLfEV20senZzv8VF+puNLheiGPlBGsv2A==}
+
+ '@next/swc-darwin-arm64@15.3.1':
+ resolution: {integrity: sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@next/swc-darwin-x64@15.3.1':
+ resolution: {integrity: sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@next/swc-linux-arm64-gnu@15.3.1':
+ resolution: {integrity: sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-arm64-musl@15.3.1':
+ resolution: {integrity: sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-x64-gnu@15.3.1':
+ resolution: {integrity: sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-linux-x64-musl@15.3.1':
+ resolution: {integrity: sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-win32-arm64-msvc@15.3.1':
+ resolution: {integrity: sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@next/swc-win32-x64-msvc@15.3.1':
+ resolution: {integrity: sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@nolyfill/is-core-module@1.0.39':
+ resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
+ engines: {node: '>=12.4.0'}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
+ '@popperjs/core@2.11.8':
+ resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
+
+ '@rtsao/scc@1.1.0':
+ resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
+
+ '@rushstack/eslint-patch@1.11.0':
+ resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==}
+
+ '@socket.io/component-emitter@3.1.2':
+ resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
+
+ '@standard-schema/utils@0.3.0':
+ resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
+
+ '@swc/counter@0.1.3':
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
+ '@swc/helpers@0.5.15':
+ resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
+
+ '@tybys/wasm-util@0.9.0':
+ resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/json5@0.0.29':
+ resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+
+ '@types/parse-json@4.0.2':
+ resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
+
+ '@types/prop-types@15.7.14':
+ resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
+
+ '@types/react-transition-group@4.4.12':
+ resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==}
+ peerDependencies:
+ '@types/react': '*'
+
+ '@types/react@19.1.2':
+ resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==}
+
+ '@typescript-eslint/eslint-plugin@8.31.1':
+ resolution: {integrity: sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.9.0'
+
+ '@typescript-eslint/parser@8.31.1':
+ resolution: {integrity: sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.9.0'
+
+ '@typescript-eslint/scope-manager@8.31.1':
+ resolution: {integrity: sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/type-utils@8.31.1':
+ resolution: {integrity: sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.9.0'
+
+ '@typescript-eslint/types@8.31.1':
+ resolution: {integrity: sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.31.1':
+ resolution: {integrity: sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <5.9.0'
+
+ '@typescript-eslint/utils@8.31.1':
+ resolution: {integrity: sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.9.0'
+
+ '@typescript-eslint/visitor-keys@8.31.1':
+ resolution: {integrity: sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@unrs/resolver-binding-darwin-arm64@1.7.2':
+ resolution: {integrity: sha512-vxtBno4xvowwNmO/ASL0Y45TpHqmNkAaDtz4Jqb+clmcVSSl8XCG/PNFFkGsXXXS6AMjP+ja/TtNCFFa1QwLRg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@unrs/resolver-binding-darwin-x64@1.7.2':
+ resolution: {integrity: sha512-qhVa8ozu92C23Hsmv0BF4+5Dyyd5STT1FolV4whNgbY6mj3kA0qsrGPe35zNR3wAN7eFict3s4Rc2dDTPBTuFQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@unrs/resolver-binding-freebsd-x64@1.7.2':
+ resolution: {integrity: sha512-zKKdm2uMXqLFX6Ac7K5ElnnG5VIXbDlFWzg4WJ8CGUedJryM5A3cTgHuGMw1+P5ziV8CRhnSEgOnurTI4vpHpg==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.2':
+ resolution: {integrity: sha512-8N1z1TbPnHH+iDS/42GJ0bMPLiGK+cUqOhNbMKtWJ4oFGzqSJk/zoXFzcQkgtI63qMcUI7wW1tq2usZQSb2jxw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.7.2':
+ resolution: {integrity: sha512-tjYzI9LcAXR9MYd9rO45m1s0B/6bJNuZ6jeOxo1pq1K6OBuRMMmfyvJYval3s9FPPGmrldYA3mi4gWDlWuTFGA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm64-gnu@1.7.2':
+ resolution: {integrity: sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-arm64-musl@1.7.2':
+ resolution: {integrity: sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
+ resolution: {integrity: sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
+ resolution: {integrity: sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
+ resolution: {integrity: sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
+ resolution: {integrity: sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.7.2':
+ resolution: {integrity: sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-x64-musl@1.7.2':
+ resolution: {integrity: sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@unrs/resolver-binding-wasm32-wasi@1.7.2':
+ resolution: {integrity: sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@unrs/resolver-binding-win32-arm64-msvc@1.7.2':
+ resolution: {integrity: sha512-gtYTh4/VREVSLA+gHrfbWxaMO/00y+34htY7XpioBTy56YN2eBjkPrY1ML1Zys89X3RJDKVaogzwxlM1qU7egg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.7.2':
+ resolution: {integrity: sha512-Ywv20XHvHTDRQs12jd3MY8X5C8KLjDbg/jyaal/QLKx3fAShhJyD4blEANInsjxW3P7isHx1Blt56iUDDJO3jg==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.7.2':
+ resolution: {integrity: sha512-friS8NEQfHaDbkThxopGk+LuE5v3iY0StruifjQEt7SLbA46OnfgMO15sOTkbpJkol6RB+1l1TYPXh0sCddpvA==}
+ cpu: [x64]
+ os: [win32]
+
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.14.1:
+ resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ ansi-escapes@4.3.2:
+ resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ array-buffer-byte-length@1.0.2:
+ resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
+ engines: {node: '>= 0.4'}
+
+ array-includes@3.1.8:
+ resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.findlast@1.2.5:
+ resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.findlastindex@1.2.6:
+ resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flat@1.3.3:
+ resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flatmap@1.3.3:
+ resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.tosorted@1.1.4:
+ resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
+ engines: {node: '>= 0.4'}
+
+ arraybuffer.prototype.slice@1.0.4:
+ resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
+ engines: {node: '>= 0.4'}
+
+ ast-types-flow@0.0.8:
+ resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
+
+ async-function@1.0.0:
+ resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
+ engines: {node: '>= 0.4'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
+ axe-core@4.10.3:
+ resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
+ engines: {node: '>=4'}
+
+ axios@1.9.0:
+ resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
+
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
+ babel-plugin-macros@3.1.0:
+ resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
+ engines: {node: '>=10', npm: '>=6'}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ bl@4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+
+ body-parser@2.2.0:
+ resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
+ engines: {node: '>=18'}
+
+ brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+ brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ buffer@5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+
+ busboy@1.6.0:
+ resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
+ engines: {node: '>=10.16.0'}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bind@1.0.8:
+ resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001717:
+ resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ chardet@0.7.0:
+ resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
+
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
+
+ cli-cursor@3.1.0:
+ resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+ engines: {node: '>=8'}
+
+ cli-spinners@2.9.2:
+ resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
+ engines: {node: '>=6'}
+
+ cli-width@3.0.0:
+ resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
+ engines: {node: '>= 10'}
+
+ client-only@0.0.1:
+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+
+ clone@1.0.4:
+ resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+ engines: {node: '>=0.8'}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ commander@7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ content-disposition@1.0.0:
+ resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ convert-source-map@1.9.0:
+ resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
+ cosmiconfig@7.1.0:
+ resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
+ engines: {node: '>=10'}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ cssjanus@2.3.0:
+ resolution: {integrity: sha512-ZZXXn51SnxRxAZ6fdY7mBDPmA4OZd83q/J9Gdqz3YmE9TUq+9tZl+tdOnCi7PpNygI6PEkehj9rgifv5+W8a5A==}
+ engines: {node: '>=10.0.0'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ damerau-levenshtein@1.0.8:
+ resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+
+ data-view-buffer@1.0.2:
+ resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-length@1.0.2:
+ resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-offset@1.0.1:
+ resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
+ engines: {node: '>= 0.4'}
+
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.3.7:
+ resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ defaults@1.0.4:
+ resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.0.4:
+ resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+ engines: {node: '>=8'}
+
+ doctrine@2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+
+ dom-helpers@5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
+ engine.io-client@6.6.3:
+ resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==}
+
+ engine.io-parser@5.2.3:
+ resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
+ engines: {node: '>=10.0.0'}
+
+ error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+
+ es-abstract@1.23.9:
+ resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
+ engines: {node: '>= 0.4'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-iterator-helpers@1.2.1:
+ resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ es-shim-unscopables@1.1.0:
+ resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
+ engines: {node: '>= 0.4'}
+
+ es-to-primitive@1.3.0:
+ resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
+ engines: {node: '>= 0.4'}
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-config-next@15.3.1:
+ resolution: {integrity: sha512-GnmyVd9TE/Ihe3RrvcafFhXErErtr2jS0JDeCSp3vWvy86AXwHsRBt0E3MqP/m8ACS1ivcsi5uaqjbhsG18qKw==}
+ peerDependencies:
+ eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
+ typescript: '>=3.3.1'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+
+ eslint-import-resolver-typescript@3.10.1:
+ resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '*'
+ eslint-plugin-import: '*'
+ eslint-plugin-import-x: '*'
+ peerDependenciesMeta:
+ eslint-plugin-import:
+ optional: true
+ eslint-plugin-import-x:
+ optional: true
+
+ eslint-module-utils@2.12.0:
+ resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: '*'
+ eslint-import-resolver-node: '*'
+ eslint-import-resolver-typescript: '*'
+ eslint-import-resolver-webpack: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ eslint:
+ optional: true
+ eslint-import-resolver-node:
+ optional: true
+ eslint-import-resolver-typescript:
+ optional: true
+ eslint-import-resolver-webpack:
+ optional: true
+
+ eslint-plugin-import@2.31.0:
+ resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+
+ eslint-plugin-jsx-a11y@6.10.2:
+ resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react@7.37.5:
+ resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+
+ eslint-scope@8.3.0:
+ resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.0:
+ resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.26.0:
+ resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.3.0:
+ resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ eventsource-parser@3.0.1:
+ resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==}
+ engines: {node: '>=18.0.0'}
+
+ eventsource@3.0.6:
+ resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==}
+ engines: {node: '>=18.0.0'}
+
+ express-rate-limit@7.5.0:
+ resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: ^4.11 || 5 || ^5.0.0-beta.1
+
+ express@5.1.0:
+ resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
+ engines: {node: '>= 18'}
+
+ external-editor@3.1.0:
+ resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
+ engines: {node: '>=4'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.1:
+ resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ fdir@6.4.4:
+ resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ figures@3.2.0:
+ resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
+ engines: {node: '>=8'}
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ finalhandler@2.1.0:
+ resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
+ engines: {node: '>= 0.8'}
+
+ find-root@1.1.0:
+ resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.3.3:
+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+ follow-redirects@1.15.9:
+ resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ for-each@0.3.5:
+ resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+ engines: {node: '>= 0.4'}
+
+ form-data@4.0.2:
+ resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
+ engines: {node: '>= 6'}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ function.prototype.name@1.1.8:
+ resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
+ engines: {node: '>= 0.4'}
+
+ functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-symbol-description@1.1.0:
+ resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
+ engines: {node: '>= 0.4'}
+
+ get-tsconfig@4.10.0:
+ resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globalthis@1.0.4:
+ resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+ engines: {node: '>= 0.4'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+ has-bigints@1.1.0:
+ resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.2.0:
+ resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ hoist-non-react-statics@3.3.2:
+ resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ immutable@5.1.1:
+ resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ inquirer@8.2.6:
+ resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==}
+ engines: {node: '>=12.0.0'}
+
+ internal-slot@1.1.0:
+ resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
+ engines: {node: '>= 0.4'}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-array-buffer@3.0.5:
+ resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
+ engines: {node: '>= 0.4'}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
+ is-async-function@2.1.1:
+ resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
+ engines: {node: '>= 0.4'}
+
+ is-bigint@1.1.0:
+ resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
+ engines: {node: '>= 0.4'}
+
+ is-boolean-object@1.2.2:
+ resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
+ engines: {node: '>= 0.4'}
+
+ is-bun-module@2.0.0:
+ resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
+
+ is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-data-view@1.0.2:
+ resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
+ engines: {node: '>= 0.4'}
+
+ is-date-object@1.1.0:
+ resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
+ engines: {node: '>= 0.4'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-finalizationregistry@1.1.1:
+ resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
+ engines: {node: '>= 0.4'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-generator-function@1.1.0:
+ resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
+ engines: {node: '>= 0.4'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-interactive@1.0.0:
+ resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
+ engines: {node: '>=8'}
+
+ is-map@2.0.3:
+ resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+ engines: {node: '>= 0.4'}
+
+ is-number-object@1.1.1:
+ resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
+ engines: {node: '>= 0.4'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
+ is-regex@1.2.1:
+ resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+ engines: {node: '>= 0.4'}
+
+ is-set@2.0.3:
+ resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+ engines: {node: '>= 0.4'}
+
+ is-shared-array-buffer@1.0.4:
+ resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
+ engines: {node: '>= 0.4'}
+
+ is-string@1.1.1:
+ resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
+ engines: {node: '>= 0.4'}
+
+ is-symbol@1.1.1:
+ resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
+ engines: {node: '>= 0.4'}
+
+ is-typed-array@1.1.15:
+ resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
+ engines: {node: '>= 0.4'}
+
+ is-unicode-supported@0.1.0:
+ resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+ engines: {node: '>=10'}
+
+ is-weakmap@2.0.2:
+ resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+ engines: {node: '>= 0.4'}
+
+ is-weakref@1.1.1:
+ resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
+ engines: {node: '>= 0.4'}
+
+ is-weakset@2.0.4:
+ resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
+ engines: {node: '>= 0.4'}
+
+ isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ iterator.prototype@1.1.5:
+ resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
+ engines: {node: '>= 0.4'}
+
+ jalali-moment@3.3.11:
+ resolution: {integrity: sha512-tdSaRs9cjWjOIaWhcsGFZMhZQhfgok5J0TwqFpBIZPudZxxa6yjUPoLCOwuvbAtRpiZn7k/mvazAJh+vEN5suw==}
+ hasBin: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json5@1.0.2:
+ resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ hasBin: true
+
+ jsx-ast-utils@3.3.5:
+ resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
+ engines: {node: '>=4.0'}
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ language-subtag-registry@0.3.23:
+ resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
+
+ language-tags@1.0.9:
+ resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
+ engines: {node: '>=0.10'}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+ log-symbols@4.1.0:
+ resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+ engines: {node: '>=10'}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@3.0.1:
+ resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
+ engines: {node: '>= 0.6'}
+
+ mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+ moment@2.30.1:
+ resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ mute-stream@0.0.8:
+ resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ napi-postinstall@0.2.3:
+ resolution: {integrity: sha512-Mi7JISo/4Ij2tDZ2xBE2WH+/KvVlkhA6juEjpEeRAVPNCpN3nxJo/5FhDNKgBcdmcmhaH6JjgST4xY/23ZYK0w==}
+ engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
+ next@15.3.1:
+ resolution: {integrity: sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==}
+ engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@opentelemetry/api': ^1.1.0
+ '@playwright/test': ^1.41.2
+ babel-plugin-react-compiler: '*'
+ react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ sass: ^1.3.0
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ '@playwright/test':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+ sass:
+ optional: true
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+
+ object.assign@4.1.7:
+ resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
+ engines: {node: '>= 0.4'}
+
+ object.entries@1.1.9:
+ resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
+ engines: {node: '>= 0.4'}
+
+ object.fromentries@2.0.8:
+ resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
+ engines: {node: '>= 0.4'}
+
+ object.groupby@1.0.3:
+ resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
+ engines: {node: '>= 0.4'}
+
+ object.values@1.2.1:
+ resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
+ engines: {node: '>= 0.4'}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ ora@5.4.1:
+ resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
+ engines: {node: '>=10'}
+
+ os-tmpdir@1.0.2:
+ resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
+ engines: {node: '>=0.10.0'}
+
+ own-keys@1.0.1:
+ resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
+ engines: {node: '>= 0.4'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-to-regexp@8.2.0:
+ resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
+ engines: {node: '>=16'}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.2:
+ resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+ engines: {node: '>=12'}
+
+ pkce-challenge@5.0.0:
+ resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==}
+ engines: {node: '>=16.20.0'}
+
+ possible-typed-array-names@1.1.0:
+ resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
+ engines: {node: '>= 0.4'}
+
+ postcss@8.4.31:
+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ prettier@3.5.3:
+ resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
+ engines: {node: '>=14'}
+ hasBin: true
+
+ prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
+ property-expr@2.0.6:
+ resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ qs@6.14.0:
+ resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+ engines: {node: '>=0.6'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@3.0.0:
+ resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
+ engines: {node: '>= 0.8'}
+
+ react-dom@19.1.0:
+ resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
+ peerDependencies:
+ react: ^19.1.0
+
+ react-hook-form@7.56.2:
+ resolution: {integrity: sha512-vpfuHuQMF/L6GpuQ4c3ZDo+pRYxIi40gQqsCmmfUBwm+oqvBhKhwghCuj2o00YCgSfU6bR9KC/xnQGWm3Gr08A==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react-is@19.1.0:
+ resolution: {integrity: sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==}
+
+ react-toastify@11.0.5:
+ resolution: {integrity: sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==}
+ peerDependencies:
+ react: ^18 || ^19
+ react-dom: ^18 || ^19
+
+ react-transition-group@4.4.5:
+ resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
+ peerDependencies:
+ react: '>=16.6.0'
+ react-dom: '>=16.6.0'
+
+ react@19.1.0:
+ resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
+ engines: {node: '>=0.10.0'}
+
+ readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
+
+ reflect.getprototypeof@1.0.10:
+ resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
+ engines: {node: '>= 0.4'}
+
+ regexp.prototype.flags@1.5.4:
+ resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
+ engines: {node: '>= 0.4'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ resolve@2.0.0-next.5:
+ resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
+ hasBin: true
+
+ restore-cursor@3.1.0:
+ resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+ engines: {node: '>=8'}
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
+ run-async@2.4.1:
+ resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
+ engines: {node: '>=0.12.0'}
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ rxjs@7.8.2:
+ resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
+
+ safe-array-concat@1.1.3:
+ resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
+ engines: {node: '>=0.4'}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safe-push-apply@1.0.0:
+ resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
+ engines: {node: '>= 0.4'}
+
+ safe-regex-test@1.1.0:
+ resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
+ engines: {node: '>= 0.4'}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ sass@1.87.0:
+ resolution: {integrity: sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.1:
+ resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ send@1.2.0:
+ resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
+ engines: {node: '>= 18'}
+
+ serve-static@2.2.0:
+ resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
+ engines: {node: '>= 18'}
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+
+ set-proto@1.0.0:
+ resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
+ engines: {node: '>= 0.4'}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ sharp@0.34.1:
+ resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+ simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
+ socket.io-client@4.8.1:
+ resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==}
+ engines: {node: '>=10.0.0'}
+
+ socket.io-parser@4.2.4:
+ resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
+ engines: {node: '>=10.0.0'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.5.7:
+ resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+ engines: {node: '>=0.10.0'}
+
+ stable-hash@0.0.5:
+ resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ streamsearch@1.1.0:
+ resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
+ engines: {node: '>=10.0.0'}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string.prototype.includes@2.0.1:
+ resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.matchall@4.0.12:
+ resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.repeat@1.0.0:
+ resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
+
+ string.prototype.trim@1.2.10:
+ resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimend@1.0.9:
+ resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimstart@1.0.8:
+ resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+ engines: {node: '>= 0.4'}
+
+ string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ styled-jsx@5.1.6:
+ resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
+ engines: {node: '>= 12.0.0'}
+ peerDependencies:
+ '@babel/core': '*'
+ babel-plugin-macros: '*'
+ react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ babel-plugin-macros:
+ optional: true
+
+ stylis-plugin-rtl@2.1.1:
+ resolution: {integrity: sha512-q6xIkri6fBufIO/sV55md2CbgS5c6gg9EhSVATtHHCdOnbN/jcI0u3lYhNVeuI65c4lQPo67g8xmq5jrREvzlg==}
+ peerDependencies:
+ stylis: 4.x
+
+ stylis@4.2.0:
+ resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
+
+ stylis@4.3.6:
+ resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ swr@2.3.3:
+ resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==}
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ through@2.3.8:
+ resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+
+ tiny-case@1.0.3:
+ resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
+
+ tinyglobby@0.2.13:
+ resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
+ engines: {node: '>=12.0.0'}
+
+ tmp@0.0.33:
+ resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
+ engines: {node: '>=0.6.0'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ toposort@2.0.2:
+ resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
+
+ ts-api-utils@2.1.0:
+ resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
+ engines: {node: '>=18.12'}
+ peerDependencies:
+ typescript: '>=4.8.4'
+
+ tsconfig-paths@3.15.0:
+ resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ type-fest@0.21.3:
+ resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+
+ type-fest@2.19.0:
+ resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
+ engines: {node: '>=12.20'}
+
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
+ typed-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-length@1.0.3:
+ resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-offset@1.0.4:
+ resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-length@1.0.7:
+ resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
+ engines: {node: '>= 0.4'}
+
+ typescript@5.8.3:
+ resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ unbox-primitive@1.1.0:
+ resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
+ engines: {node: '>= 0.4'}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
+ unrs-resolver@1.7.2:
+ resolution: {integrity: sha512-BBKpaylOW8KbHsu378Zky/dGh4ckT/4NW/0SHRABdqRLcQJ2dAOjDo9g97p04sWflm0kqPqpUatxReNV/dqI5A==}
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ use-sync-external-store@1.5.0:
+ resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ wcwidth@1.0.1:
+ resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+
+ which-boxed-primitive@1.1.1:
+ resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
+ engines: {node: '>= 0.4'}
+
+ which-builtin-type@1.2.1:
+ resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
+ engines: {node: '>= 0.4'}
+
+ which-collection@1.0.2:
+ resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+ engines: {node: '>= 0.4'}
+
+ which-typed-array@1.1.19:
+ resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
+ engines: {node: '>= 0.4'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ wrap-ansi@6.2.0:
+ resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+ engines: {node: '>=8'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ ws@8.17.1:
+ resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ xmlhttprequest-ssl@2.1.2:
+ resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==}
+ engines: {node: '>=0.4.0'}
+
+ yaml@1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+ yup@1.6.1:
+ resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==}
+
+ zod-to-json-schema@3.24.5:
+ resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
+ peerDependencies:
+ zod: ^3.24.1
+
+ zod@3.24.4:
+ resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==}
+
+snapshots:
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/generator@7.27.1':
+ dependencies:
+ '@babel/parser': 7.27.1
+ '@babel/types': 7.27.1
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.1.0
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.27.1
+ '@babel/types': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/parser@7.27.1':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/runtime@7.27.1': {}
+
+ '@babel/template@7.27.1':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.27.1
+ '@babel/types': 7.27.1
+
+ '@babel/traverse@7.27.1':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.1
+ '@babel/parser': 7.27.1
+ '@babel/template': 7.27.1
+ '@babel/types': 7.27.1
+ debug: 4.4.0
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.27.1':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@emnapi/core@1.4.3':
+ dependencies:
+ '@emnapi/wasi-threads': 1.0.2
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.4.3':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.0.2':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emotion/babel-plugin@11.13.5':
+ dependencies:
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/runtime': 7.27.1
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/serialize': 1.3.3
+ babel-plugin-macros: 3.1.0
+ convert-source-map: 1.9.0
+ escape-string-regexp: 4.0.0
+ find-root: 1.1.0
+ source-map: 0.5.7
+ stylis: 4.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/cache@11.14.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+ '@emotion/sheet': 1.4.0
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ stylis: 4.2.0
+
+ '@emotion/hash@0.9.2': {}
+
+ '@emotion/is-prop-valid@1.3.1':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
+ '@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0)
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ hoist-non-react-statics: 3.3.2
+ react: 19.1.0
+ optionalDependencies:
+ '@types/react': 19.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/serialize@1.3.3':
+ dependencies:
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/unitless': 0.10.0
+ '@emotion/utils': 1.4.2
+ csstype: 3.1.3
+
+ '@emotion/sheet@1.4.0': {}
+
+ '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/is-prop-valid': 1.3.1
+ '@emotion/react': 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0)
+ '@emotion/utils': 1.4.2
+ react: 19.1.0
+ optionalDependencies:
+ '@types/react': 19.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/unitless@0.10.0': {}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.1.0)':
+ dependencies:
+ react: 19.1.0
+
+ '@emotion/utils@1.4.2': {}
+
+ '@emotion/weak-memoize@0.4.0': {}
+
+ '@eslint-community/eslint-utils@4.7.0(eslint@9.26.0)':
+ dependencies:
+ eslint: 9.26.0
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.1': {}
+
+ '@eslint/config-array@0.20.0':
+ dependencies:
+ '@eslint/object-schema': 2.1.6
+ debug: 4.4.0
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.2.2': {}
+
+ '@eslint/core@0.13.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.1':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.0
+ espree: 10.3.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.26.0': {}
+
+ '@eslint/object-schema@2.1.6': {}
+
+ '@eslint/plugin-kit@0.2.8':
+ dependencies:
+ '@eslint/core': 0.13.0
+ levn: 0.4.1
+
+ '@hookform/resolvers@5.0.1(react-hook-form@7.56.2(react@19.1.0))':
+ dependencies:
+ '@standard-schema/utils': 0.3.0
+ react-hook-form: 7.56.2(react@19.1.0)
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.6':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.3.1
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.3.1': {}
+
+ '@humanwhocodes/retry@0.4.2': {}
+
+ '@img/sharp-darwin-arm64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.1.0
+ optional: true
+
+ '@img/sharp-darwin-x64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.1.0
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-ppc64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.1.0':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.1.0
+ optional: true
+
+ '@img/sharp-linux-arm@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.1.0
+ optional: true
+
+ '@img/sharp-linux-s390x@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.1.0
+ optional: true
+
+ '@img/sharp-linux-x64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.1.0
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.34.1':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.1.0
+ optional: true
+
+ '@img/sharp-wasm32@0.34.1':
+ dependencies:
+ '@emnapi/runtime': 1.4.3
+ optional: true
+
+ '@img/sharp-win32-ia32@0.34.1':
+ optional: true
+
+ '@img/sharp-win32-x64@0.34.1':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.8':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@modelcontextprotocol/sdk@1.11.0':
+ dependencies:
+ content-type: 1.0.5
+ cors: 2.8.5
+ cross-spawn: 7.0.6
+ eventsource: 3.0.6
+ express: 5.1.0
+ express-rate-limit: 7.5.0(express@5.1.0)
+ pkce-challenge: 5.0.0
+ raw-body: 3.0.0
+ zod: 3.24.4
+ zod-to-json-schema: 3.24.5(zod@3.24.4)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@mui/core-downloads-tracker@7.0.2': {}
+
+ '@mui/icons-material@7.0.2(@mui/material@7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@mui/material': 7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ react: 19.1.0
+ optionalDependencies:
+ '@types/react': 19.1.2
+
+ '@mui/material-nextjs@7.0.2(@emotion/cache@11.14.0)(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.87.0))(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@emotion/react': 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ next: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.87.0)
+ react: 19.1.0
+ optionalDependencies:
+ '@emotion/cache': 11.14.0
+ '@types/react': 19.1.2
+
+ '@mui/material@7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@mui/core-downloads-tracker': 7.0.2
+ '@mui/system': 7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+ '@mui/types': 7.4.1(@types/react@19.1.2)
+ '@mui/utils': 7.0.2(@types/react@19.1.2)(react@19.1.0)
+ '@popperjs/core': 2.11.8
+ '@types/react-transition-group': 4.4.12(@types/react@19.1.2)
+ clsx: 2.1.1
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ react-is: 19.1.0
+ react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+ '@types/react': 19.1.2
+
+ '@mui/private-theming@7.0.2(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@mui/utils': 7.0.2(@types/react@19.1.2)(react@19.1.0)
+ prop-types: 15.8.1
+ react: 19.1.0
+ optionalDependencies:
+ '@types/react': 19.1.2
+
+ '@mui/styled-engine@7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/sheet': 1.4.0
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.0
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+
+ '@mui/system@7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@mui/private-theming': 7.0.2(@types/react@19.1.2)(react@19.1.0)
+ '@mui/styled-engine': 7.0.2(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0))(react@19.1.0)
+ '@mui/types': 7.4.1(@types/react@19.1.2)
+ '@mui/utils': 7.0.2(@types/react@19.1.2)(react@19.1.0)
+ clsx: 2.1.1
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.0
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.2)(react@19.1.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.2)(react@19.1.0))(@types/react@19.1.2)(react@19.1.0)
+ '@types/react': 19.1.2
+
+ '@mui/types@7.4.1(@types/react@19.1.2)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ optionalDependencies:
+ '@types/react': 19.1.2
+
+ '@mui/utils@7.0.2(@types/react@19.1.2)(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.27.1
+ '@mui/types': 7.4.1(@types/react@19.1.2)
+ '@types/prop-types': 15.7.14
+ clsx: 2.1.1
+ prop-types: 15.8.1
+ react: 19.1.0
+ react-is: 19.1.0
+ optionalDependencies:
+ '@types/react': 19.1.2
+
+ '@napi-rs/wasm-runtime@0.2.9':
+ dependencies:
+ '@emnapi/core': 1.4.3
+ '@emnapi/runtime': 1.4.3
+ '@tybys/wasm-util': 0.9.0
+ optional: true
+
+ '@next/env@15.3.1': {}
+
+ '@next/eslint-plugin-next@15.3.1':
+ dependencies:
+ fast-glob: 3.3.1
+
+ '@next/swc-darwin-arm64@15.3.1':
+ optional: true
+
+ '@next/swc-darwin-x64@15.3.1':
+ optional: true
+
+ '@next/swc-linux-arm64-gnu@15.3.1':
+ optional: true
+
+ '@next/swc-linux-arm64-musl@15.3.1':
+ optional: true
+
+ '@next/swc-linux-x64-gnu@15.3.1':
+ optional: true
+
+ '@next/swc-linux-x64-musl@15.3.1':
+ optional: true
+
+ '@next/swc-win32-arm64-msvc@15.3.1':
+ optional: true
+
+ '@next/swc-win32-x64-msvc@15.3.1':
+ optional: true
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.19.1
+
+ '@nolyfill/is-core-module@1.0.39': {}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+ optional: true
+
+ '@popperjs/core@2.11.8': {}
+
+ '@rtsao/scc@1.1.0': {}
+
+ '@rushstack/eslint-patch@1.11.0': {}
+
+ '@socket.io/component-emitter@3.1.2': {}
+
+ '@standard-schema/utils@0.3.0': {}
+
+ '@swc/counter@0.1.3': {}
+
+ '@swc/helpers@0.5.15':
+ dependencies:
+ tslib: 2.8.1
+
+ '@tybys/wasm-util@0.9.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/estree@1.0.7': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/json5@0.0.29': {}
+
+ '@types/parse-json@4.0.2': {}
+
+ '@types/prop-types@15.7.14': {}
+
+ '@types/react-transition-group@4.4.12(@types/react@19.1.2)':
+ dependencies:
+ '@types/react': 19.1.2
+
+ '@types/react@19.1.2':
+ dependencies:
+ csstype: 3.1.3
+
+ '@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ '@typescript-eslint/scope-manager': 8.31.1
+ '@typescript-eslint/type-utils': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.31.1
+ eslint: 9.26.0
+ graphemer: 1.4.0
+ ignore: 5.3.2
+ natural-compare: 1.4.0
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.31.1
+ '@typescript-eslint/types': 8.31.1
+ '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.31.1
+ debug: 4.4.0
+ eslint: 9.26.0
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.31.1':
+ dependencies:
+ '@typescript-eslint/types': 8.31.1
+ '@typescript-eslint/visitor-keys': 8.31.1
+
+ '@typescript-eslint/type-utils@8.31.1(eslint@9.26.0)(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ debug: 4.4.0
+ eslint: 9.26.0
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.31.1': {}
+
+ '@typescript-eslint/typescript-estree@8.31.1(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/types': 8.31.1
+ '@typescript-eslint/visitor-keys': 8.31.1
+ debug: 4.4.0
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.1
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.31.1(eslint@9.26.0)(typescript@5.8.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0)
+ '@typescript-eslint/scope-manager': 8.31.1
+ '@typescript-eslint/types': 8.31.1
+ '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
+ eslint: 9.26.0
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.31.1':
+ dependencies:
+ '@typescript-eslint/types': 8.31.1
+ eslint-visitor-keys: 4.2.0
+
+ '@unrs/resolver-binding-darwin-arm64@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-darwin-x64@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-freebsd-x64@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm64-gnu@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm64-musl@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-musl@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-wasm32-wasi@1.7.2':
+ dependencies:
+ '@napi-rs/wasm-runtime': 0.2.9
+ optional: true
+
+ '@unrs/resolver-binding-win32-arm64-msvc@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.7.2':
+ optional: true
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.7.2':
+ optional: true
+
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.1
+ negotiator: 1.0.0
+
+ acorn-jsx@5.3.2(acorn@8.14.1):
+ dependencies:
+ acorn: 8.14.1
+
+ acorn@8.14.1: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-escapes@4.3.2:
+ dependencies:
+ type-fest: 0.21.3
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ aria-query@5.3.2: {}
+
+ array-buffer-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ is-array-buffer: 3.0.5
+
+ array-includes@3.1.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ is-string: 1.1.1
+
+ array.prototype.findlast@1.2.5:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.findlastindex@1.2.6:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flat@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flatmap@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.tosorted@1.1.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-shim-unscopables: 1.1.0
+
+ arraybuffer.prototype.slice@1.0.4:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ is-array-buffer: 3.0.5
+
+ ast-types-flow@0.0.8: {}
+
+ async-function@1.0.0: {}
+
+ asynckit@0.4.0: {}
+
+ available-typed-arrays@1.0.7:
+ dependencies:
+ possible-typed-array-names: 1.1.0
+
+ axe-core@4.10.3: {}
+
+ axios@1.9.0:
+ dependencies:
+ follow-redirects: 1.15.9
+ form-data: 4.0.2
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
+ axobject-query@4.1.0: {}
+
+ babel-plugin-macros@3.1.0:
+ dependencies:
+ '@babel/runtime': 7.27.1
+ cosmiconfig: 7.1.0
+ resolve: 1.22.10
+
+ balanced-match@1.0.2: {}
+
+ base64-js@1.5.1: {}
+
+ bl@4.1.0:
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+
+ body-parser@2.2.0:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.0
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ on-finished: 2.4.1
+ qs: 6.14.0
+ raw-body: 3.0.0
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ brace-expansion@1.1.11:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.1:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ buffer@5.7.1:
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
+ busboy@1.6.0:
+ dependencies:
+ streamsearch: 1.1.0
+
+ bytes@3.1.2: {}
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bind@1.0.8:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ get-intrinsic: 1.3.0
+ set-function-length: 1.2.2
+
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001717: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ chardet@0.7.0: {}
+
+ chokidar@4.0.3:
+ dependencies:
+ readdirp: 4.1.2
+
+ cli-cursor@3.1.0:
+ dependencies:
+ restore-cursor: 3.1.0
+
+ cli-spinners@2.9.2: {}
+
+ cli-width@3.0.0: {}
+
+ client-only@0.0.1: {}
+
+ clone@1.0.4: {}
+
+ clsx@2.1.1: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+ optional: true
+
+ color@4.2.3:
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+ optional: true
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ commander@7.2.0: {}
+
+ concat-map@0.0.1: {}
+
+ content-disposition@1.0.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ content-type@1.0.5: {}
+
+ convert-source-map@1.9.0: {}
+
+ cookie-signature@1.2.2: {}
+
+ cookie@0.7.2: {}
+
+ cors@2.8.5:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
+ cosmiconfig@7.1.0:
+ dependencies:
+ '@types/parse-json': 4.0.2
+ import-fresh: 3.3.1
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ cssjanus@2.3.0: {}
+
+ csstype@3.1.3: {}
+
+ damerau-levenshtein@1.0.8: {}
+
+ data-view-buffer@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-offset@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.3.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ defaults@1.0.4:
+ dependencies:
+ clone: 1.0.4
+
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ define-properties@1.2.1:
+ dependencies:
+ define-data-property: 1.1.4
+ has-property-descriptors: 1.0.2
+ object-keys: 1.1.1
+
+ delayed-stream@1.0.0: {}
+
+ depd@2.0.0: {}
+
+ dequal@2.0.3: {}
+
+ detect-libc@1.0.3:
+ optional: true
+
+ detect-libc@2.0.4:
+ optional: true
+
+ doctrine@2.1.0:
+ dependencies:
+ esutils: 2.0.3
+
+ dom-helpers@5.2.1:
+ dependencies:
+ '@babel/runtime': 7.27.1
+ csstype: 3.1.3
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ ee-first@1.1.1: {}
+
+ emoji-regex@8.0.0: {}
+
+ emoji-regex@9.2.2: {}
+
+ encodeurl@2.0.0: {}
+
+ engine.io-client@6.6.3:
+ dependencies:
+ '@socket.io/component-emitter': 3.1.2
+ debug: 4.3.7
+ engine.io-parser: 5.2.3
+ ws: 8.17.1
+ xmlhttprequest-ssl: 2.1.2
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ engine.io-parser@5.2.3: {}
+
+ error-ex@1.3.2:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ es-abstract@1.23.9:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ arraybuffer.prototype.slice: 1.0.4
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ data-view-buffer: 1.0.2
+ data-view-byte-length: 1.0.2
+ data-view-byte-offset: 1.0.1
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-set-tostringtag: 2.1.0
+ es-to-primitive: 1.3.0
+ function.prototype.name: 1.1.8
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ get-symbol-description: 1.1.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ internal-slot: 1.1.0
+ is-array-buffer: 3.0.5
+ is-callable: 1.2.7
+ is-data-view: 1.0.2
+ is-regex: 1.2.1
+ is-shared-array-buffer: 1.0.4
+ is-string: 1.1.1
+ is-typed-array: 1.1.15
+ is-weakref: 1.1.1
+ math-intrinsics: 1.1.0
+ object-inspect: 1.13.4
+ object-keys: 1.1.1
+ object.assign: 4.1.7
+ own-keys: 1.0.1
+ regexp.prototype.flags: 1.5.4
+ safe-array-concat: 1.1.3
+ safe-push-apply: 1.0.0
+ safe-regex-test: 1.1.0
+ set-proto: 1.0.0
+ string.prototype.trim: 1.2.10
+ string.prototype.trimend: 1.0.9
+ string.prototype.trimstart: 1.0.8
+ typed-array-buffer: 1.0.3
+ typed-array-byte-length: 1.0.3
+ typed-array-byte-offset: 1.0.4
+ typed-array-length: 1.0.7
+ unbox-primitive: 1.1.0
+ which-typed-array: 1.1.19
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-iterator-helpers@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-set-tostringtag: 2.1.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ iterator.prototype: 1.1.5
+ safe-array-concat: 1.1.3
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ es-shim-unscopables@1.1.0:
+ dependencies:
+ hasown: 2.0.2
+
+ es-to-primitive@1.3.0:
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.1.0
+ is-symbol: 1.1.1
+
+ escape-html@1.0.3: {}
+
+ escape-string-regexp@1.0.5: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-config-next@15.3.1(eslint@9.26.0)(typescript@5.8.3):
+ dependencies:
+ '@next/eslint-plugin-next': 15.3.1
+ '@rushstack/eslint-patch': 1.11.0
+ '@typescript-eslint/eslint-plugin': 8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ eslint: 9.26.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0)
+ eslint-plugin-jsx-a11y: 6.10.2(eslint@9.26.0)
+ eslint-plugin-react: 7.37.5(eslint@9.26.0)
+ eslint-plugin-react-hooks: 5.2.0(eslint@9.26.0)
+ optionalDependencies:
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - eslint-import-resolver-webpack
+ - eslint-plugin-import-x
+ - supports-color
+
+ eslint-import-resolver-node@0.3.9:
+ dependencies:
+ debug: 3.2.7
+ is-core-module: 2.16.1
+ resolve: 1.22.10
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0):
+ dependencies:
+ '@nolyfill/is-core-module': 1.0.39
+ debug: 4.4.0
+ eslint: 9.26.0
+ get-tsconfig: 4.10.0
+ is-bun-module: 2.0.0
+ stable-hash: 0.0.5
+ tinyglobby: 0.2.13
+ unrs-resolver: 1.7.2
+ optionalDependencies:
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0):
+ dependencies:
+ debug: 3.2.7
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ eslint: 9.26.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0):
+ dependencies:
+ '@rtsao/scc': 1.1.0
+ array-includes: 3.1.8
+ array.prototype.findlastindex: 1.2.6
+ array.prototype.flat: 1.3.3
+ array.prototype.flatmap: 1.3.3
+ debug: 3.2.7
+ doctrine: 2.1.0
+ eslint: 9.26.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0)
+ hasown: 2.0.2
+ is-core-module: 2.16.1
+ is-glob: 4.0.3
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ object.groupby: 1.0.3
+ object.values: 1.2.1
+ semver: 6.3.1
+ string.prototype.trimend: 1.0.9
+ tsconfig-paths: 3.15.0
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.31.1(eslint@9.26.0)(typescript@5.8.3)
+ transitivePeerDependencies:
+ - eslint-import-resolver-typescript
+ - eslint-import-resolver-webpack
+ - supports-color
+
+ eslint-plugin-jsx-a11y@6.10.2(eslint@9.26.0):
+ dependencies:
+ aria-query: 5.3.2
+ array-includes: 3.1.8
+ array.prototype.flatmap: 1.3.3
+ ast-types-flow: 0.0.8
+ axe-core: 4.10.3
+ axobject-query: 4.1.0
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ eslint: 9.26.0
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ language-tags: 1.0.9
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ safe-regex-test: 1.1.0
+ string.prototype.includes: 2.0.1
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.26.0):
+ dependencies:
+ eslint: 9.26.0
+
+ eslint-plugin-react@7.37.5(eslint@9.26.0):
+ dependencies:
+ array-includes: 3.1.8
+ array.prototype.findlast: 1.2.5
+ array.prototype.flatmap: 1.3.3
+ array.prototype.tosorted: 1.1.4
+ doctrine: 2.1.0
+ es-iterator-helpers: 1.2.1
+ eslint: 9.26.0
+ estraverse: 5.3.0
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ minimatch: 3.1.2
+ object.entries: 1.1.9
+ object.fromentries: 2.0.8
+ object.values: 1.2.1
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.5
+ semver: 6.3.1
+ string.prototype.matchall: 4.0.12
+ string.prototype.repeat: 1.0.0
+
+ eslint-scope@8.3.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.0: {}
+
+ eslint@9.26.0:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0)
+ '@eslint-community/regexpp': 4.12.1
+ '@eslint/config-array': 0.20.0
+ '@eslint/config-helpers': 0.2.2
+ '@eslint/core': 0.13.0
+ '@eslint/eslintrc': 3.3.1
+ '@eslint/js': 9.26.0
+ '@eslint/plugin-kit': 0.2.8
+ '@humanfs/node': 0.16.6
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.2
+ '@modelcontextprotocol/sdk': 1.11.0
+ '@types/estree': 1.0.7
+ '@types/json-schema': 7.0.15
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.3.0
+ eslint-visitor-keys: 4.2.0
+ espree: 10.3.0
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ zod: 3.24.4
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.3.0:
+ dependencies:
+ acorn: 8.14.1
+ acorn-jsx: 5.3.2(acorn@8.14.1)
+ eslint-visitor-keys: 4.2.0
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ etag@1.8.1: {}
+
+ eventsource-parser@3.0.1: {}
+
+ eventsource@3.0.6:
+ dependencies:
+ eventsource-parser: 3.0.1
+
+ express-rate-limit@7.5.0(express@5.1.0):
+ dependencies:
+ express: 5.1.0
+
+ express@5.1.0:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.0
+ content-disposition: 1.0.0
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.0
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.1
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.14.0
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.0
+ serve-static: 2.2.0
+ statuses: 2.0.1
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ external-editor@3.1.0:
+ dependencies:
+ chardet: 0.7.0
+ iconv-lite: 0.4.24
+ tmp: 0.0.33
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.1:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fastq@1.19.1:
+ dependencies:
+ reusify: 1.1.0
+
+ fdir@6.4.4(picomatch@4.0.2):
+ optionalDependencies:
+ picomatch: 4.0.2
+
+ figures@3.2.0:
+ dependencies:
+ escape-string-regexp: 1.0.5
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ finalhandler@2.1.0:
+ dependencies:
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ find-root@1.1.0: {}
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.3
+ keyv: 4.5.4
+
+ flatted@3.3.3: {}
+
+ follow-redirects@1.15.9: {}
+
+ for-each@0.3.5:
+ dependencies:
+ is-callable: 1.2.7
+
+ form-data@4.0.2:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ mime-types: 2.1.35
+
+ forwarded@0.2.0: {}
+
+ fresh@2.0.0: {}
+
+ function-bind@1.1.2: {}
+
+ function.prototype.name@1.1.8:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ functions-have-names: 1.2.3
+ hasown: 2.0.2
+ is-callable: 1.2.7
+
+ functions-have-names@1.2.3: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ get-symbol-description@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+
+ get-tsconfig@4.10.0:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@11.12.0: {}
+
+ globals@14.0.0: {}
+
+ globalthis@1.0.4:
+ dependencies:
+ define-properties: 1.2.1
+ gopd: 1.2.0
+
+ gopd@1.2.0: {}
+
+ graphemer@1.4.0: {}
+
+ has-bigints@1.1.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.1
+
+ has-proto@1.2.0:
+ dependencies:
+ dunder-proto: 1.0.1
+
+ has-symbols@1.1.0: {}
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ hoist-non-react-statics@3.3.2:
+ dependencies:
+ react-is: 16.13.1
+
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
+ iconv-lite@0.4.24:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ ieee754@1.2.1: {}
+
+ ignore@5.3.2: {}
+
+ immutable@5.1.1: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ inherits@2.0.4: {}
+
+ inquirer@8.2.6:
+ dependencies:
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ cli-cursor: 3.1.0
+ cli-width: 3.0.0
+ external-editor: 3.1.0
+ figures: 3.2.0
+ lodash: 4.17.21
+ mute-stream: 0.0.8
+ ora: 5.4.1
+ run-async: 2.4.1
+ rxjs: 7.8.2
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ through: 2.3.8
+ wrap-ansi: 6.2.0
+
+ internal-slot@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.1.0
+
+ ipaddr.js@1.9.1: {}
+
+ is-array-buffer@3.0.5:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ is-arrayish@0.2.1: {}
+
+ is-arrayish@0.3.2:
+ optional: true
+
+ is-async-function@2.1.1:
+ dependencies:
+ async-function: 1.0.0
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-bigint@1.1.0:
+ dependencies:
+ has-bigints: 1.1.0
+
+ is-boolean-object@1.2.2:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-bun-module@2.0.0:
+ dependencies:
+ semver: 7.7.1
+
+ is-callable@1.2.7: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-data-view@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ is-typed-array: 1.1.15
+
+ is-date-object@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-extglob@2.1.1: {}
+
+ is-finalizationregistry@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-generator-function@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-interactive@1.0.0: {}
+
+ is-map@2.0.3: {}
+
+ is-number-object@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-number@7.0.0: {}
+
+ is-promise@4.0.0: {}
+
+ is-regex@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ is-set@2.0.3: {}
+
+ is-shared-array-buffer@1.0.4:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-string@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-symbol@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-symbols: 1.1.0
+ safe-regex-test: 1.1.0
+
+ is-typed-array@1.1.15:
+ dependencies:
+ which-typed-array: 1.1.19
+
+ is-unicode-supported@0.1.0: {}
+
+ is-weakmap@2.0.2: {}
+
+ is-weakref@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-weakset@2.0.4:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ isarray@2.0.5: {}
+
+ isexe@2.0.0: {}
+
+ iterator.prototype@1.1.5:
+ dependencies:
+ define-data-property: 1.1.4
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ has-symbols: 1.1.0
+ set-function-name: 2.0.2
+
+ jalali-moment@3.3.11:
+ dependencies:
+ commander: 7.2.0
+ inquirer: 8.2.6
+ moment: 2.30.1
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@1.0.2:
+ dependencies:
+ minimist: 1.2.8
+
+ jsx-ast-utils@3.3.5:
+ dependencies:
+ array-includes: 3.1.8
+ array.prototype.flat: 1.3.3
+ object.assign: 4.1.7
+ object.values: 1.2.1
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ language-subtag-registry@0.3.23: {}
+
+ language-tags@1.0.9:
+ dependencies:
+ language-subtag-registry: 0.3.23
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ lines-and-columns@1.2.4: {}
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.merge@4.6.2: {}
+
+ lodash@4.17.21: {}
+
+ log-symbols@4.1.0:
+ dependencies:
+ chalk: 4.1.2
+ is-unicode-supported: 0.1.0
+
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
+ lz-string@1.5.0: {}
+
+ math-intrinsics@1.1.0: {}
+
+ media-typer@1.1.0: {}
+
+ merge-descriptors@2.0.0: {}
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mime-db@1.52.0: {}
+
+ mime-db@1.54.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ mime-types@3.0.1:
+ dependencies:
+ mime-db: 1.54.0
+
+ mimic-fn@2.1.0: {}
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.11
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ minimist@1.2.8: {}
+
+ moment@2.30.1: {}
+
+ ms@2.1.3: {}
+
+ mute-stream@0.0.8: {}
+
+ nanoid@3.3.11: {}
+
+ napi-postinstall@0.2.3: {}
+
+ natural-compare@1.4.0: {}
+
+ negotiator@1.0.0: {}
+
+ next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.87.0):
+ dependencies:
+ '@next/env': 15.3.1
+ '@swc/counter': 0.1.3
+ '@swc/helpers': 0.5.15
+ busboy: 1.6.0
+ caniuse-lite: 1.0.30001717
+ postcss: 8.4.31
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ styled-jsx: 5.1.6(react@19.1.0)
+ optionalDependencies:
+ '@next/swc-darwin-arm64': 15.3.1
+ '@next/swc-darwin-x64': 15.3.1
+ '@next/swc-linux-arm64-gnu': 15.3.1
+ '@next/swc-linux-arm64-musl': 15.3.1
+ '@next/swc-linux-x64-gnu': 15.3.1
+ '@next/swc-linux-x64-musl': 15.3.1
+ '@next/swc-win32-arm64-msvc': 15.3.1
+ '@next/swc-win32-x64-msvc': 15.3.1
+ sass: 1.87.0
+ sharp: 0.34.1
+ transitivePeerDependencies:
+ - '@babel/core'
+ - babel-plugin-macros
+
+ node-addon-api@7.1.1:
+ optional: true
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.4: {}
+
+ object-keys@1.1.1: {}
+
+ object.assign@4.1.7:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+ has-symbols: 1.1.0
+ object-keys: 1.1.1
+
+ object.entries@1.1.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ object.fromentries@2.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-object-atoms: 1.1.1
+
+ object.groupby@1.0.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+
+ object.values@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ onetime@5.1.2:
+ dependencies:
+ mimic-fn: 2.1.0
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ ora@5.4.1:
+ dependencies:
+ bl: 4.1.0
+ chalk: 4.1.2
+ cli-cursor: 3.1.0
+ cli-spinners: 2.9.2
+ is-interactive: 1.0.0
+ is-unicode-supported: 0.1.0
+ log-symbols: 4.1.0
+ strip-ansi: 6.0.1
+ wcwidth: 1.0.1
+
+ os-tmpdir@1.0.2: {}
+
+ own-keys@1.0.1:
+ dependencies:
+ get-intrinsic: 1.3.0
+ object-keys: 1.1.1
+ safe-push-apply: 1.0.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ parseurl@1.3.3: {}
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ path-to-regexp@8.2.0: {}
+
+ path-type@4.0.0: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.2: {}
+
+ pkce-challenge@5.0.0: {}
+
+ possible-typed-array-names@1.1.0: {}
+
+ postcss@8.4.31:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ prettier@3.5.3: {}
+
+ prop-types@15.8.1:
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ property-expr@2.0.6: {}
+
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
+ proxy-from-env@1.1.0: {}
+
+ punycode@2.3.1: {}
+
+ qs@6.14.0:
+ dependencies:
+ side-channel: 1.1.0
+
+ queue-microtask@1.2.3: {}
+
+ range-parser@1.2.1: {}
+
+ raw-body@3.0.0:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ unpipe: 1.0.0
+
+ react-dom@19.1.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ scheduler: 0.26.0
+
+ react-hook-form@7.56.2(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+
+ react-is@16.13.1: {}
+
+ react-is@19.1.0: {}
+
+ react-toastify@11.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ clsx: 2.1.1
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+
+ react-transition-group@4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ '@babel/runtime': 7.27.1
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+
+ react@19.1.0: {}
+
+ readable-stream@3.6.2:
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+
+ readdirp@4.1.2: {}
+
+ reflect.getprototypeof@1.0.10:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ which-builtin-type: 1.2.1
+
+ regexp.prototype.flags@1.5.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ set-function-name: 2.0.2
+
+ resolve-from@4.0.0: {}
+
+ resolve-pkg-maps@1.0.0: {}
+
+ resolve@1.22.10:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ resolve@2.0.0-next.5:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ restore-cursor@3.1.0:
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+
+ reusify@1.1.0: {}
+
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.0
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ run-async@2.4.1: {}
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ rxjs@7.8.2:
+ dependencies:
+ tslib: 2.8.1
+
+ safe-array-concat@1.1.3:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ has-symbols: 1.1.0
+ isarray: 2.0.5
+
+ safe-buffer@5.2.1: {}
+
+ safe-push-apply@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ isarray: 2.0.5
+
+ safe-regex-test@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-regex: 1.2.1
+
+ safer-buffer@2.1.2: {}
+
+ sass@1.87.0:
+ dependencies:
+ chokidar: 4.0.3
+ immutable: 5.1.1
+ source-map-js: 1.2.1
+ optionalDependencies:
+ '@parcel/watcher': 2.5.1
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ semver@7.7.1: {}
+
+ send@1.2.0:
+ dependencies:
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ mime-types: 3.0.1
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@2.2.0:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+
+ set-function-name@2.0.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
+
+ set-proto@1.0.0:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+
+ setprototypeof@1.2.0: {}
+
+ sharp@0.34.1:
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.4
+ semver: 7.7.1
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.34.1
+ '@img/sharp-darwin-x64': 0.34.1
+ '@img/sharp-libvips-darwin-arm64': 1.1.0
+ '@img/sharp-libvips-darwin-x64': 1.1.0
+ '@img/sharp-libvips-linux-arm': 1.1.0
+ '@img/sharp-libvips-linux-arm64': 1.1.0
+ '@img/sharp-libvips-linux-ppc64': 1.1.0
+ '@img/sharp-libvips-linux-s390x': 1.1.0
+ '@img/sharp-libvips-linux-x64': 1.1.0
+ '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
+ '@img/sharp-libvips-linuxmusl-x64': 1.1.0
+ '@img/sharp-linux-arm': 0.34.1
+ '@img/sharp-linux-arm64': 0.34.1
+ '@img/sharp-linux-s390x': 0.34.1
+ '@img/sharp-linux-x64': 0.34.1
+ '@img/sharp-linuxmusl-arm64': 0.34.1
+ '@img/sharp-linuxmusl-x64': 0.34.1
+ '@img/sharp-wasm32': 0.34.1
+ '@img/sharp-win32-ia32': 0.34.1
+ '@img/sharp-win32-x64': 0.34.1
+ optional: true
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ side-channel-list@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ signal-exit@3.0.7: {}
+
+ simple-swizzle@0.2.2:
+ dependencies:
+ is-arrayish: 0.3.2
+ optional: true
+
+ socket.io-client@4.8.1:
+ dependencies:
+ '@socket.io/component-emitter': 3.1.2
+ debug: 4.3.7
+ engine.io-client: 6.6.3
+ socket.io-parser: 4.2.4
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ socket.io-parser@4.2.4:
+ dependencies:
+ '@socket.io/component-emitter': 3.1.2
+ debug: 4.3.7
+ transitivePeerDependencies:
+ - supports-color
+
+ source-map-js@1.2.1: {}
+
+ source-map@0.5.7: {}
+
+ stable-hash@0.0.5: {}
+
+ statuses@2.0.1: {}
+
+ streamsearch@1.1.0: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ string.prototype.includes@2.0.1:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+
+ string.prototype.matchall@4.0.12:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ regexp.prototype.flags: 1.5.4
+ set-function-name: 2.0.2
+ side-channel: 1.1.0
+
+ string.prototype.repeat@1.0.0:
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+
+ string.prototype.trim@1.2.10:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-data-property: 1.1.4
+ define-properties: 1.2.1
+ es-abstract: 1.23.9
+ es-object-atoms: 1.1.1
+ has-property-descriptors: 1.0.2
+
+ string.prototype.trimend@1.0.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ string.prototype.trimstart@1.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ string_decoder@1.3.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-bom@3.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
+ styled-jsx@5.1.6(react@19.1.0):
+ dependencies:
+ client-only: 0.0.1
+ react: 19.1.0
+
+ stylis-plugin-rtl@2.1.1(stylis@4.3.6):
+ dependencies:
+ cssjanus: 2.3.0
+ stylis: 4.3.6
+
+ stylis@4.2.0: {}
+
+ stylis@4.3.6: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ swr@2.3.3(react@19.1.0):
+ dependencies:
+ dequal: 2.0.3
+ react: 19.1.0
+ use-sync-external-store: 1.5.0(react@19.1.0)
+
+ through@2.3.8: {}
+
+ tiny-case@1.0.3: {}
+
+ tinyglobby@0.2.13:
+ dependencies:
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+
+ tmp@0.0.33:
+ dependencies:
+ os-tmpdir: 1.0.2
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toidentifier@1.0.1: {}
+
+ toposort@2.0.2: {}
+
+ ts-api-utils@2.1.0(typescript@5.8.3):
+ dependencies:
+ typescript: 5.8.3
+
+ tsconfig-paths@3.15.0:
+ dependencies:
+ '@types/json5': 0.0.29
+ json5: 1.0.2
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+
+ tslib@2.8.1: {}
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ type-fest@0.21.3: {}
+
+ type-fest@2.19.0: {}
+
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.1
+
+ typed-array-buffer@1.0.3:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-length@1.0.3:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-offset@1.0.4:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+ reflect.getprototypeof: 1.0.10
+
+ typed-array-length@1.0.7:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ is-typed-array: 1.1.15
+ possible-typed-array-names: 1.1.0
+ reflect.getprototypeof: 1.0.10
+
+ typescript@5.8.3: {}
+
+ unbox-primitive@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-bigints: 1.1.0
+ has-symbols: 1.1.0
+ which-boxed-primitive: 1.1.1
+
+ unpipe@1.0.0: {}
+
+ unrs-resolver@1.7.2:
+ dependencies:
+ napi-postinstall: 0.2.3
+ optionalDependencies:
+ '@unrs/resolver-binding-darwin-arm64': 1.7.2
+ '@unrs/resolver-binding-darwin-x64': 1.7.2
+ '@unrs/resolver-binding-freebsd-x64': 1.7.2
+ '@unrs/resolver-binding-linux-arm-gnueabihf': 1.7.2
+ '@unrs/resolver-binding-linux-arm-musleabihf': 1.7.2
+ '@unrs/resolver-binding-linux-arm64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-arm64-musl': 1.7.2
+ '@unrs/resolver-binding-linux-ppc64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-riscv64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-riscv64-musl': 1.7.2
+ '@unrs/resolver-binding-linux-s390x-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-x64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-x64-musl': 1.7.2
+ '@unrs/resolver-binding-wasm32-wasi': 1.7.2
+ '@unrs/resolver-binding-win32-arm64-msvc': 1.7.2
+ '@unrs/resolver-binding-win32-ia32-msvc': 1.7.2
+ '@unrs/resolver-binding-win32-x64-msvc': 1.7.2
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ use-sync-external-store@1.5.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+
+ util-deprecate@1.0.2: {}
+
+ vary@1.1.2: {}
+
+ wcwidth@1.0.1:
+ dependencies:
+ defaults: 1.0.4
+
+ which-boxed-primitive@1.1.1:
+ dependencies:
+ is-bigint: 1.1.0
+ is-boolean-object: 1.2.2
+ is-number-object: 1.1.1
+ is-string: 1.1.1
+ is-symbol: 1.1.1
+
+ which-builtin-type@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ function.prototype.name: 1.1.8
+ has-tostringtag: 1.0.2
+ is-async-function: 2.1.1
+ is-date-object: 1.1.0
+ is-finalizationregistry: 1.1.1
+ is-generator-function: 1.1.0
+ is-regex: 1.2.1
+ is-weakref: 1.1.1
+ isarray: 2.0.5
+ which-boxed-primitive: 1.1.1
+ which-collection: 1.0.2
+ which-typed-array: 1.1.19
+
+ which-collection@1.0.2:
+ dependencies:
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-weakmap: 2.0.2
+ is-weakset: 2.0.4
+
+ which-typed-array@1.1.19:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ for-each: 0.3.5
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ wrap-ansi@6.2.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrappy@1.0.2: {}
+
+ ws@8.17.1: {}
+
+ xmlhttprequest-ssl@2.1.2: {}
+
+ yaml@1.10.2: {}
+
+ yocto-queue@0.1.0: {}
+
+ yup@1.6.1:
+ dependencies:
+ property-expr: 2.0.6
+ tiny-case: 1.0.3
+ toposort: 2.0.2
+ type-fest: 2.19.0
+
+ zod-to-json-schema@3.24.5(zod@3.24.4):
+ dependencies:
+ zod: 3.24.4
+
+ zod@3.24.4: {}
diff --git a/public/fontiran.css b/public/fontiran.css
deleted file mode 100644
index 86d585d..0000000
--- a/public/fontiran.css
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
-*
-* 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');
-}
diff --git a/public/icons/favicon.png b/public/icons/favicon.png
deleted file mode 100644
index c82bf9a..0000000
Binary files a/public/icons/favicon.png and /dev/null differ
diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json
deleted file mode 100644
index 7d89691..0000000
--- a/public/locales/fa/app.json
+++ /dev/null
@@ -1,273 +0,0 @@
-{
- "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": "پست الکترونیک",
- "telephone_id": "کد تلفن",
- "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" : "لطفا توضیحات خود را وارد نمایید"
- }
-}
diff --git a/public/locales/fa/datatable.js b/public/locales/fa/datatable.js
deleted file mode 100644
index fd43663..0000000
--- a/public/locales/fa/datatable.js
+++ /dev/null
@@ -1,92 +0,0 @@
-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: "بدون مرتب سازی",
-};
diff --git a/public/manifest.json b/public/manifest.json
deleted file mode 100644
index 9246992..0000000
--- a/public/manifest.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "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"
- ]
-}
diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/loading.jsx b/src/app/(withAuth)/(dashboardLayout)/dashboard/loading.jsx
new file mode 100644
index 0000000..6469168
--- /dev/null
+++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/loading.jsx
@@ -0,0 +1,7 @@
+"use client";
+import PageLoading from "@/core/components/PageLoading";
+
+const Loading = () => {
+ return ;
+};
+export default Loading;
diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/page.js
new file mode 100644
index 0000000..ed0df92
--- /dev/null
+++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/page.js
@@ -0,0 +1,9 @@
+export const metadata = {
+ title: "پیشخوان",
+};
+
+const Page = () => {
+ return <>>;
+};
+
+export default Page;
diff --git a/src/app/(withAuth)/(dashboardLayout)/layout.js b/src/app/(withAuth)/(dashboardLayout)/layout.js
new file mode 100644
index 0000000..c6cc316
--- /dev/null
+++ b/src/app/(withAuth)/(dashboardLayout)/layout.js
@@ -0,0 +1,19 @@
+import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
+import CallWidget from "@/components/widget/call";
+import WithWidgetMiddleware from "@/core/middlewares/withWidget";
+import { SocketProvider } from "@/lib/contexts/socket";
+import { Stack } from "@mui/material";
+
+const Layout = ({ children }) => {
+ return (
+
+
+ {children}
+
+
+
+
+
+ );
+};
+export default Layout;
diff --git a/src/app/(withAuth)/layout.js b/src/app/(withAuth)/layout.js
new file mode 100644
index 0000000..315d04e
--- /dev/null
+++ b/src/app/(withAuth)/layout.js
@@ -0,0 +1,7 @@
+import WithAuthMiddleware from "@/core/middlewares/withAuth";
+
+const Layout = ({ children }) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/(withoutAuth)/layout.js b/src/app/(withoutAuth)/layout.js
new file mode 100644
index 0000000..d3d734f
--- /dev/null
+++ b/src/app/(withoutAuth)/layout.js
@@ -0,0 +1,13 @@
+"use client";
+import WithoutAuthMiddleware from "@/core/middlewares/withoutAuth";
+import { Suspense } from "react";
+
+const Layout = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default Layout;
diff --git a/src/app/(withoutAuth)/login/page.js b/src/app/(withoutAuth)/login/page.js
new file mode 100644
index 0000000..74eab32
--- /dev/null
+++ b/src/app/(withoutAuth)/login/page.js
@@ -0,0 +1,10 @@
+import LoginPage from "@/components/Login";
+
+export const metadata = {
+ title: "ورود",
+};
+
+const Page = () => {
+ return ;
+};
+export default Page;
diff --git a/src/app/default.js b/src/app/default.js
new file mode 100644
index 0000000..6ddf1b7
--- /dev/null
+++ b/src/app/default.js
@@ -0,0 +1,3 @@
+export default function Default() {
+ return null;
+}
diff --git a/src/app/layout.js b/src/app/layout.js
new file mode 100644
index 0000000..4c01ad4
--- /dev/null
+++ b/src/app/layout.js
@@ -0,0 +1,29 @@
+import { Rtl } from "@/core/utils/cacheRtl";
+import { AuthProvider } from "@/lib/contexts/auth";
+import { TableSettingProvider } from "@/lib/contexts/tableSetting";
+import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
+
+export const metadata = {
+ title: {
+ template: "%s | سامانه CRM",
+ default: "سامانه CRM",
+ },
+};
+
+export default function RootLayout({ children }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/src/app/not-found.js b/src/app/not-found.js
new file mode 100644
index 0000000..7174a75
--- /dev/null
+++ b/src/app/not-found.js
@@ -0,0 +1,21 @@
+"use client";
+import { Box, Stack, Typography } from "@mui/material";
+import SvgNotFound from "@/core/components/svgs/SvgNotFound";
+
+export default function NotFound() {
+ return (
+
+
+
+
+
+ صفحه موردنظر یافت نشد ...
+
+
+ );
+}
diff --git a/src/app/page.js b/src/app/page.js
new file mode 100644
index 0000000..651714b
--- /dev/null
+++ b/src/app/page.js
@@ -0,0 +1,8 @@
+import { redirect } from "next/navigation";
+
+function Page() {
+ redirect("/dashboard", "replace");
+ return null;
+}
+
+export default Page;
diff --git a/src/app/template.js b/src/app/template.js
new file mode 100644
index 0000000..505ebf8
--- /dev/null
+++ b/src/app/template.js
@@ -0,0 +1,40 @@
+"use client";
+import "@/assets/scss/fontiran.scss";
+import "@/assets/scss/global.scss";
+import theme from "@/core/utils/theme";
+import { CssBaseline, GlobalStyles, ThemeProvider } from "@mui/material";
+
+import { ToastContainer } from "react-toastify";
+
+const Template = ({ children }) => {
+ return (
+
+
+
+ {children}
+
+
+
+
+ );
+};
+
+export default Template;
diff --git a/public/fonts/eot/IRANSansWeb(FaNum).eot b/src/assets/fonts/eot/IRANSansWeb(FaNum).eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum).eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum).eot
diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Black.eot b/src/assets/fonts/eot/IRANSansWeb(FaNum)_Black.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum)_Black.eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum)_Black.eot
diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot b/src/assets/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Light.eot b/src/assets/fonts/eot/IRANSansWeb(FaNum)_Light.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum)_Light.eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum)_Light.eot
diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot b/src/assets/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
diff --git a/public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot b/src/assets/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
rename to src/assets/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
diff --git a/public/fonts/eot/IRANSansWeb.eot b/src/assets/fonts/eot/IRANSansWeb.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb.eot
rename to src/assets/fonts/eot/IRANSansWeb.eot
diff --git a/public/fonts/eot/IRANSansWeb_Black.eot b/src/assets/fonts/eot/IRANSansWeb_Black.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb_Black.eot
rename to src/assets/fonts/eot/IRANSansWeb_Black.eot
diff --git a/public/fonts/eot/IRANSansWeb_Bold.eot b/src/assets/fonts/eot/IRANSansWeb_Bold.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb_Bold.eot
rename to src/assets/fonts/eot/IRANSansWeb_Bold.eot
diff --git a/public/fonts/eot/IRANSansWeb_Light.eot b/src/assets/fonts/eot/IRANSansWeb_Light.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb_Light.eot
rename to src/assets/fonts/eot/IRANSansWeb_Light.eot
diff --git a/public/fonts/eot/IRANSansWeb_Medium.eot b/src/assets/fonts/eot/IRANSansWeb_Medium.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb_Medium.eot
rename to src/assets/fonts/eot/IRANSansWeb_Medium.eot
diff --git a/public/fonts/eot/IRANSansWeb_UltraLight.eot b/src/assets/fonts/eot/IRANSansWeb_UltraLight.eot
similarity index 100%
rename from public/fonts/eot/IRANSansWeb_UltraLight.eot
rename to src/assets/fonts/eot/IRANSansWeb_UltraLight.eot
diff --git a/public/fonts/eot/Parastoo-Bold.eot b/src/assets/fonts/eot/Parastoo-Bold.eot
similarity index 100%
rename from public/fonts/eot/Parastoo-Bold.eot
rename to src/assets/fonts/eot/Parastoo-Bold.eot
diff --git a/public/fonts/eot/Parastoo.eot b/src/assets/fonts/eot/Parastoo.eot
similarity index 100%
rename from public/fonts/eot/Parastoo.eot
rename to src/assets/fonts/eot/Parastoo.eot
diff --git a/src/assets/fonts/ttf/BNazanin.ttf b/src/assets/fonts/ttf/BNazanin.ttf
new file mode 100644
index 0000000..4e59251
Binary files /dev/null and b/src/assets/fonts/ttf/BNazanin.ttf differ
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum).ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum).ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum).ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum).ttf
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
diff --git a/public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf b/src/assets/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
rename to src/assets/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
diff --git a/public/fonts/ttf/IRANSansWeb.ttf b/src/assets/fonts/ttf/IRANSansWeb.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb.ttf
rename to src/assets/fonts/ttf/IRANSansWeb.ttf
diff --git a/public/fonts/ttf/IRANSansWeb_Black.ttf b/src/assets/fonts/ttf/IRANSansWeb_Black.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb_Black.ttf
rename to src/assets/fonts/ttf/IRANSansWeb_Black.ttf
diff --git a/public/fonts/ttf/IRANSansWeb_Bold.ttf b/src/assets/fonts/ttf/IRANSansWeb_Bold.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb_Bold.ttf
rename to src/assets/fonts/ttf/IRANSansWeb_Bold.ttf
diff --git a/public/fonts/ttf/IRANSansWeb_Light.ttf b/src/assets/fonts/ttf/IRANSansWeb_Light.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb_Light.ttf
rename to src/assets/fonts/ttf/IRANSansWeb_Light.ttf
diff --git a/public/fonts/ttf/IRANSansWeb_Medium.ttf b/src/assets/fonts/ttf/IRANSansWeb_Medium.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb_Medium.ttf
rename to src/assets/fonts/ttf/IRANSansWeb_Medium.ttf
diff --git a/public/fonts/ttf/IRANSansWeb_UltraLight.ttf b/src/assets/fonts/ttf/IRANSansWeb_UltraLight.ttf
similarity index 100%
rename from public/fonts/ttf/IRANSansWeb_UltraLight.ttf
rename to src/assets/fonts/ttf/IRANSansWeb_UltraLight.ttf
diff --git a/public/fonts/ttf/Parastoo-Bold.ttf b/src/assets/fonts/ttf/Parastoo-Bold.ttf
similarity index 100%
rename from public/fonts/ttf/Parastoo-Bold.ttf
rename to src/assets/fonts/ttf/Parastoo-Bold.ttf
diff --git a/public/fonts/ttf/Parastoo.ttf b/src/assets/fonts/ttf/Parastoo.ttf
similarity index 100%
rename from public/fonts/ttf/Parastoo.ttf
rename to src/assets/fonts/ttf/Parastoo.ttf
diff --git a/public/fonts/woff/IRANSansWeb(FaNum).woff b/src/assets/fonts/woff/IRANSansWeb(FaNum).woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum).woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum).woff
diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Black.woff b/src/assets/fonts/woff/IRANSansWeb(FaNum)_Black.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum)_Black.woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum)_Black.woff
diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff b/src/assets/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Light.woff b/src/assets/fonts/woff/IRANSansWeb(FaNum)_Light.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum)_Light.woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum)_Light.woff
diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff b/src/assets/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
diff --git a/public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff b/src/assets/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
rename to src/assets/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
diff --git a/public/fonts/woff/IRANSansWeb.woff b/src/assets/fonts/woff/IRANSansWeb.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb.woff
rename to src/assets/fonts/woff/IRANSansWeb.woff
diff --git a/public/fonts/woff/IRANSansWeb_Black.woff b/src/assets/fonts/woff/IRANSansWeb_Black.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb_Black.woff
rename to src/assets/fonts/woff/IRANSansWeb_Black.woff
diff --git a/public/fonts/woff/IRANSansWeb_Bold.woff b/src/assets/fonts/woff/IRANSansWeb_Bold.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb_Bold.woff
rename to src/assets/fonts/woff/IRANSansWeb_Bold.woff
diff --git a/public/fonts/woff/IRANSansWeb_Light.woff b/src/assets/fonts/woff/IRANSansWeb_Light.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb_Light.woff
rename to src/assets/fonts/woff/IRANSansWeb_Light.woff
diff --git a/public/fonts/woff/IRANSansWeb_Medium.woff b/src/assets/fonts/woff/IRANSansWeb_Medium.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb_Medium.woff
rename to src/assets/fonts/woff/IRANSansWeb_Medium.woff
diff --git a/public/fonts/woff/IRANSansWeb_UltraLight.woff b/src/assets/fonts/woff/IRANSansWeb_UltraLight.woff
similarity index 100%
rename from public/fonts/woff/IRANSansWeb_UltraLight.woff
rename to src/assets/fonts/woff/IRANSansWeb_UltraLight.woff
diff --git a/public/fonts/woff/Parastoo-Bold.woff b/src/assets/fonts/woff/Parastoo-Bold.woff
similarity index 100%
rename from public/fonts/woff/Parastoo-Bold.woff
rename to src/assets/fonts/woff/Parastoo-Bold.woff
diff --git a/public/fonts/woff/Parastoo.woff b/src/assets/fonts/woff/Parastoo.woff
similarity index 100%
rename from public/fonts/woff/Parastoo.woff
rename to src/assets/fonts/woff/Parastoo.woff
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum).woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum).woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum).woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum).woff2
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
diff --git a/public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2 b/src/assets/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
rename to src/assets/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
diff --git a/public/fonts/woff2/IRANSansWeb.woff2 b/src/assets/fonts/woff2/IRANSansWeb.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb.woff2
rename to src/assets/fonts/woff2/IRANSansWeb.woff2
diff --git a/public/fonts/woff2/IRANSansWeb_Black.woff2 b/src/assets/fonts/woff2/IRANSansWeb_Black.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb_Black.woff2
rename to src/assets/fonts/woff2/IRANSansWeb_Black.woff2
diff --git a/public/fonts/woff2/IRANSansWeb_Bold.woff2 b/src/assets/fonts/woff2/IRANSansWeb_Bold.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb_Bold.woff2
rename to src/assets/fonts/woff2/IRANSansWeb_Bold.woff2
diff --git a/public/fonts/woff2/IRANSansWeb_Light.woff2 b/src/assets/fonts/woff2/IRANSansWeb_Light.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb_Light.woff2
rename to src/assets/fonts/woff2/IRANSansWeb_Light.woff2
diff --git a/public/fonts/woff2/IRANSansWeb_Medium.woff2 b/src/assets/fonts/woff2/IRANSansWeb_Medium.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb_Medium.woff2
rename to src/assets/fonts/woff2/IRANSansWeb_Medium.woff2
diff --git a/public/fonts/woff2/IRANSansWeb_UltraLight.woff2 b/src/assets/fonts/woff2/IRANSansWeb_UltraLight.woff2
similarity index 100%
rename from public/fonts/woff2/IRANSansWeb_UltraLight.woff2
rename to src/assets/fonts/woff2/IRANSansWeb_UltraLight.woff2
diff --git a/src/assets/images/empty_list.svg b/src/assets/images/empty_list.svg
new file mode 100644
index 0000000..2c5b6bd
--- /dev/null
+++ b/src/assets/images/empty_list.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/images/examine_marker.png b/src/assets/images/examine_marker.png
new file mode 100644
index 0000000..ac2446d
Binary files /dev/null and b/src/assets/images/examine_marker.png differ
diff --git a/src/assets/images/examine_marker_active.png b/src/assets/images/examine_marker_active.png
new file mode 100644
index 0000000..07cbca5
Binary files /dev/null and b/src/assets/images/examine_marker_active.png differ
diff --git a/src/assets/images/locationMarker.png b/src/assets/images/locationMarker.png
new file mode 100644
index 0000000..5e19b95
Binary files /dev/null and b/src/assets/images/locationMarker.png differ
diff --git a/src/assets/scss/fontiran.scss b/src/assets/scss/fontiran.scss
new file mode 100644
index 0000000..6aaa085
--- /dev/null
+++ b/src/assets/scss/fontiran.scss
@@ -0,0 +1,212 @@
+@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");
+}
+
+@font-face {
+ font-family: Bnazanin;
+ font-style: normal;
+ font-weight: normal;
+ src: url("../fonts/ttf/BNazanin.ttf") format("truetype");
+}
diff --git a/src/assets/scss/global.scss b/src/assets/scss/global.scss
new file mode 100644
index 0000000..ec424d5
--- /dev/null
+++ b/src/assets/scss/global.scss
@@ -0,0 +1,6 @@
+.filter-toast {
+ box-shadow:
+ rgba(50, 50, 93, 0.25) 0px 13px 27px -5px,
+ rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
+ background-color: #d0dfe8;
+}
diff --git a/src/components/Login/Form/index.jsx b/src/components/Login/Form/index.jsx
new file mode 100644
index 0000000..99ae58d
--- /dev/null
+++ b/src/components/Login/Form/index.jsx
@@ -0,0 +1,128 @@
+"use client";
+import LtrTextField from "@/core/components/LtrTextField";
+import StyledForm from "@/core/components/StyledForm";
+import { GET_USER_LOGIN_ROUTE } from "@/core/utils/routes";
+import { useAuth } from "@/lib/contexts/auth";
+import useRequest from "@/lib/hooks/useRequest";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { Button, Container, Stack, Typography } from "@mui/material";
+import { Controller, useForm } from "react-hook-form";
+import { object, string } from "yup";
+
+const LoginForm = () => {
+ const requestServer = useRequest();
+ const { getUser } = useAuth();
+ const defaultValues = {
+ username: "",
+ password: "",
+ };
+
+ const validationSchema = object({
+ username: string().required("لطفا نام کاربری را وارد کنید!"),
+ password: string().required("لطفا رمز عبور را وارد کنید!"),
+ });
+
+ const {
+ control,
+ handleSubmit,
+ formState: { isSubmitting },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(validationSchema),
+ mode: "all",
+ });
+
+ const onSubmit = async (data) => {
+ try {
+ const formData = new FormData();
+ formData.append("username", data.username);
+ formData.append("password", data.password);
+ await requestServer(GET_USER_LOGIN_ROUTE, "post", {
+ data: formData,
+ });
+ getUser();
+ } catch (error) {
+ console.error("Login error:", error);
+ }
+ };
+
+ return (
+
+
+
+
+
+ ورود به سامانه CRM
+
+
+
+
+ {
+ return (
+
+ );
+ }}
+ name={"username"}
+ />
+ {
+ return (
+
+ );
+ }}
+ name={"password"}
+ />
+
+
+
+
+
+
+
+
+ );
+};
+export default LoginForm;
diff --git a/src/components/Login/LoginLinkRouting.jsx b/src/components/Login/LoginLinkRouting.jsx
new file mode 100644
index 0000000..83c5165
--- /dev/null
+++ b/src/components/Login/LoginLinkRouting.jsx
@@ -0,0 +1,25 @@
+"use client";
+import { Button, Stack } from "@mui/material";
+import Link from "next/link";
+import { useSearchParams } from "next/navigation";
+
+const LoginLinkRouting = () => {
+ const searchParams = useSearchParams();
+
+ const redirect = searchParams.get("redirect");
+
+ return (
+
+
+
+ );
+};
+export default LoginLinkRouting;
diff --git a/src/components/Login/index.jsx b/src/components/Login/index.jsx
new file mode 100644
index 0000000..d0f485d
--- /dev/null
+++ b/src/components/Login/index.jsx
@@ -0,0 +1,19 @@
+"use client";
+import { Fade, Stack } from "@mui/material";
+import LoginForm from "./Form";
+import LoginLinkRouting from "./LoginLinkRouting";
+import { Suspense } from "react";
+
+const LoginPage = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+export default LoginPage;
diff --git a/src/components/dashboard/change-password/change-password-form/__test__/index.test.js b/src/components/dashboard/change-password/change-password-form/__test__/index.test.js
deleted file mode 100644
index 503b571..0000000
--- a/src/components/dashboard/change-password/change-password-form/__test__/index.test.js
+++ /dev/null
@@ -1,305 +0,0 @@
-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();
- const changePasswordElement = screen.getByRole('heading', { level: 4 });
- expect(changePasswordElement).toHaveTextContent('تغییر رمز عبور');
- });
- it('Should see the label for current password field', () => {
- render();
- const currentPasswordLabel = screen.queryByLabelText('رمز عبور فعلی');
- expect(currentPasswordLabel).toBeInTheDocument();
- });
- it('Should see the label for new password field', () => {
- render();
- const newPasswordLabel = screen.queryByLabelText('رمز عبور جدید');
- expect(newPasswordLabel).toBeInTheDocument();
- });
- it('Should see the label for confirm password field', () => {
- render();
- const confirmPasswordLabel = screen.queryByLabelText('تکرار رمز عبور جدید');
- expect(confirmPasswordLabel).toBeInTheDocument();
- });
- it('Should see the submit button with the submit label and should be disable', () => {
- render();
- 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();
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- // 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();
-
- // 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();
-
- // 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- // 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();
- 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');
- });
- });
- });
-})
\ No newline at end of file
diff --git a/src/components/dashboard/change-password/change-password-form/index.js b/src/components/dashboard/change-password/change-password-form/index.js
deleted file mode 100644
index 9b7704a..0000000
--- a/src/components/dashboard/change-password/change-password-form/index.js
+++ /dev/null
@@ -1,137 +0,0 @@
-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 (
-
- {(props) => (
- {
- e.preventDefault();
- props.handleSubmit();
- }}
- >
-
-
-
- {t("ChangePassword.typography_change_password")}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- );
-};
-
-export default ChangePasswordForm;
diff --git a/src/components/dashboard/change-password/index.jsx b/src/components/dashboard/change-password/index.jsx
deleted file mode 100644
index 74896a6..0000000
--- a/src/components/dashboard/change-password/index.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-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 (
-
-
-
-
-
-
-
- );
-};
-export default DashboardChangePasswordComponent;
diff --git a/src/components/dashboard/edit-profile/index.jsx b/src/components/dashboard/edit-profile/index.jsx
deleted file mode 100644
index d15d467..0000000
--- a/src/components/dashboard/edit-profile/index.jsx
+++ /dev/null
@@ -1,198 +0,0 @@
-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 {UPDATE_AVATAR} from "@/core/data/apiRoutes";
-import useDirection from "@/lib/app/hooks/useDirection";
-import ImageResizer from "@/core/components/ImageConvertor";
-import useRequest from "@/lib/app/hooks/useRequest";
-
-const DashboardEditProfile = () => {
- const t = useTranslations();
- const requestServer = useRequest({auth: true})
- const {user, token, getUser, changeUser} = useUser();
- const {directionApp} = useDirection();
-
- const editAvatar = async (avatar) => {
- try {
- const formData = new FormData();
-
- if (avatar != null) {
- var resizedAvatar;
- resizedAvatar = await ImageResizer(avatar);
- formData.append("avatar", resizedAvatar);
- }
- await requestServer(UPDATE_AVATAR, 'post', {formData}).then((response) => {
- })
- .catch(() => {
- }).finally(() => {
- });
- } catch (error) {
- throw error;
- }
- };
- const handleSubmit = (values, {setSubmitting}) => {
-
- };
- const initialValues = {
- expert_avatar: null,
- username: user.username,
- name: user.name,
- email: user.email,
- province_name: user.province_name,
- position: user.position,
- };
- const validationSchema = Yup.object().shape({});
-
- return (
-
-
-
-
- {(props) => (
- {
- e.preventDefault();
- props.handleSubmit();
- }}
- >
-
-
-
- {t("UpdateProfile.typography_edit_profile")}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
-
- );
-};
-
-export default DashboardEditProfile;
diff --git a/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js b/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js
deleted file mode 100644
index cfc0a60..0000000
--- a/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js
+++ /dev/null
@@ -1,35 +0,0 @@
-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();
- const idHeader = screen.queryByText("کد یکتا");
- const nameHeader = screen.queryByText("نام کامل");
- const usernameHeader = screen.queryByText("نام کاربری");
- const emailHeader = screen.queryByText("پست الکترونیک");
- const telephone_idHeader = 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(telephone_idHeader).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();
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/DataTable/index.jsx b/src/components/dashboard/expert-management/DataTable/index.jsx
deleted file mode 100644
index 41dd1e6..0000000
--- a/src/components/dashboard/expert-management/DataTable/index.jsx
+++ /dev/null
@@ -1,202 +0,0 @@
-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}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.full_name,
- id: "full_name",
- header: t("ExpertMangement.name"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.username,
- id: "username",
- header: t("ExpertMangement.username"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.email,
- id: "email",
- header: t("ExpertMangement.email"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.telephone_id,
- id: "telephone_id",
- header: t("ExpertMangement.telephone_id"),
- enableColumnFilter: true,
- datatype: "numeric",
- filterFn: "equals",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue}
- ),
- },
- {
- 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}) => (
- {renderedCellValue}
- ),
- },
- {
- 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}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.position,
- id: "position",
- header: t("ExpertMangement.position"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue}
- ),
- },
- {
- 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}) => (
- {renderedCellValue}
- ),
- },
- {
- 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}) => (
- {renderedCellValue}
- ),
- },
- {
- accessorFn: (row) => row.gender,
- id: "gender",
- header: t("ExpertMangement.gender"),
- enableColumnFilter: false,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => (
- {renderedCellValue === "male" ? t("ExpertMangement.male") : t("ExpertMangement.female")}
- ),
- },
- {
- 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 {renderedCellValue};
- },
- Header: ({column}) => <>{column.columnDef.header}>,
- Filter: ({column}) => {
- return (
-
- );
- },
- },
- ],
- []
- );
- return (
-
-
-
- );
-}
-
-export default ExpertManagementDataTable;
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/ChangePassword/index.jsx b/src/components/dashboard/expert-management/Form/ChangePassword/index.jsx
deleted file mode 100644
index ea3d11c..0000000
--- a/src/components/dashboard/expert-management/Form/ChangePassword/index.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-const ChangePassword = () => {
- return (
- <>>
- )
-}
-
-export default ChangePassword
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/__tests__/index.test.js
deleted file mode 100644
index 913c37a..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/__tests__/index.test.js
+++ /dev/null
@@ -1,219 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-
-describe("PersonalInfo Component From Expert Management (create)", () => {
- describe("Rendering", () => {
- it("full_name TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const fullNameTextField = screen.queryByLabelText('نام کامل');
- expect(fullNameTextField).toBeInTheDocument();
- });
- });
- it("Email TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const emailTextField = screen.queryByLabelText('پست الکترونیک');
- expect(emailTextField).toBeInTheDocument();
- });
- });
- it("Phone Number TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
- expect(phoneNumberTextField).toBeInTheDocument();
- });
- });
- it("telephone id TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
- expect(telephoneIdTextField).toBeInTheDocument();
- });
- });
- it("National Id TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const nationalIdTextField = screen.queryByLabelText('کد ملی');
- expect(nationalIdTextField).toBeInTheDocument();
- });
- });
- it("Gender Select Box Rendered", async () => {
- render();
- await waitFor(() => {
- const genderSelectBox = screen.getByTestId('select-box');
- expect(genderSelectBox).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Name TextField Work Correctly", async () => {
- render();
- const nameTextField = screen.queryByLabelText('نام کامل');
- fireEvent.change(nameTextField, {target: {value: 'exampleName'}});
- await act(() => {
- expect(nameTextField).toHaveValue('exampleName');
- })
- });
- it("Email TextField Work Correctly", async () => {
- render();
- const emailTextField = screen.queryByLabelText('پست الکترونیک');
- fireEvent.change(emailTextField, {target: {value: 'exampleEmail'}});
- await act(() => {
- expect(emailTextField).toHaveValue('exampleEmail');
- })
- });
- it("Phone Number TextField Work Correctly", async () => {
- render();
- const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
- fireEvent.change(phoneNumberTextField, {target: {value: 'examplePhoneNumber'}});
- await act(() => {
- expect(phoneNumberTextField).toHaveValue('examplePhoneNumber');
- })
- });
- it("Telephone Id TextField Work Correctly", async () => {
- render();
- const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
- fireEvent.change(telephoneIdTextField, {target: {value: 'exampleTelephoneId'}});
- await act(() => {
- expect(telephoneIdTextField).toHaveValue('exampleTelephoneId');
- })
- });
- it("National Id TextField Work Correctly", async () => {
- render();
- const nationalIdTextField = screen.queryByLabelText('کد ملی');
- fireEvent.change(nationalIdTextField, {target: {value: 'exampleNationalId'}});
- await act(() => {
- expect(nationalIdTextField).toHaveValue('exampleNationalId');
- })
- });
- it("Gender Select Box Work Correctly", async () => {
- render();
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/index.jsx
deleted file mode 100644
index f92bf38..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo/index.jsx
+++ /dev/null
@@ -1,128 +0,0 @@
-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 (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {t("ExpertMangement.text_field_gender")}
-
-
- {formik.touched.gender && formik.errors.gender ? formik.errors.gender : ""}
-
-
-
-
- )
-}
-export default PersonalInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/__tests__/index.test.js
deleted file mode 100644
index 6f32bac..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/__tests__/index.test.js
+++ /dev/null
@@ -1,96 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("PositionAndRole Component From Expert Management (create)", () => {
- describe("Rendering", () => {
- it("Position TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const positionTextField = screen.queryByLabelText('سمت');
- expect(positionTextField).toBeInTheDocument();
- });
- });
- it("Role Select Box Rendered", async () => {
- render();
- const roleSelect = screen.getByTestId('select-box');
- await waitFor(() => {
- expect(roleSelect).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Position TextField Work Correctly", async () => {
- render();
- const positionTextField = screen.queryByLabelText('سمت');
- fireEvent.change(positionTextField, {target: {value: 'examplePosition'}});
- await waitFor(() => {
- expect(positionTextField).toHaveValue('examplePosition');
- })
- });
- it("Role Select Box Work Correctly", async () => {
- render();
- 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();
-
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/index.jsx
deleted file mode 100644
index 6befbff..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/PositionAndRole/index.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-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 (
-
-
-
-
-
-
- {t("ExpertMangement.text_field_roles")}
-
-
- {formik.touched.roles && formik.errors.roles ? formik.errors.roles : ""}
-
-
-
-
- )
-}
-export default PositionAndRole
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/__tests__/index.test.js
deleted file mode 100644
index 87da19f..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/__tests__/index.test.js
+++ /dev/null
@@ -1,71 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("Province Component From Expert Management (create)", () => {
- describe("Rendering", () => {
- it("Province Select Box Rendered", async () => {
- render();
- await waitFor(() => {
- const provinceSelectBox = screen.getByTestId('select-box');
- expect(provinceSelectBox).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Province Select Box Work Correctly", async () => {
- render();
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/index.jsx
deleted file mode 100644
index 5ac94b2..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/Province/index.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-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 (
-
-
-
- {t("ExpertMangement.text_field_province_id")}
-
-
- {formik.touched.province_id && formik.errors.province_id ? formik.errors.province_id : ""}
-
-
-
-
- )
-}
-export default Province
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/index.jsx
deleted file mode 100644
index 072c096..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo/index.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import Province from "./Province";
-import PositionAndRole from "./PositionAndRole";
-
-const RestInfo = ({formik}) => {
- return (
- <>
-
-
- >
- )
-}
-export default RestInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/__test__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/__test__/index.test.js
deleted file mode 100644
index 519cf9d..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/__test__/index.test.js
+++ /dev/null
@@ -1,123 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("UserInfo Component From Expert Management (create)", () => {
- describe("Rendering", () => {
- it("UserName TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const usernameTextField = screen.queryByLabelText('نام کاربری');
- expect(usernameTextField).toBeInTheDocument();
- });
- });
- it("Password TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const passwordTextField = screen.queryByLabelText('رمز عبور');
- expect(passwordTextField).toBeInTheDocument();
- });
-
- });
- });
- describe("Behavioral", () => {
- it("Username TextField Work Correctly", async () => {
- render();
- const usernameTextField = screen.queryByLabelText('نام کاربری');
- fireEvent.change(usernameTextField, {target: {value: 'exampleUsername'}});
- await act(() => {
- expect(usernameTextField).toHaveValue('exampleUsername');
- })
- });
- it("Password TextField Work Correctly", async () => {
- render();
- 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();
-
- 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();
-
- 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();
-
- 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()
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/index.jsx
deleted file mode 100644
index 2455b26..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo/index.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-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 (
- <>
-
-
-
-
-
-
-
- {showPassword ? : }
-
-
- ),
- }}
- sx={{width: "100%"}}
- />
-
-
- >
- )
-}
-export default UserInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js
deleted file mode 100644
index 85751c5..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/__tests__/index.test.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import React from 'react';
-import CreateContent from "../../CreateContent";
-import MockAppWithProviders from "../../../../../../../../mocks/AppWithProvider";
-
-function selectDropdownItem(screen, openerTestId, itemText) {
- const opener = screen.getByTestId(openerTestId);
- fireEvent.mouseDown(opener);
- const selectItem = screen.queryByText(itemText);
- fireEvent.click(selectItem);
-}
-
-function setInputValue(screen, inputElement, value) {
- fireEvent.change(inputElement, {target: {value}});
-}
-
-describe("CreateContent Component From Expert Management (create)", () => {
- describe("Rendering", () => {
- it("close button Rendered", async () => {
- render();
- await waitFor(() => {
- const cancelBtn = screen.queryByText('بستن');
- expect(cancelBtn).toBeInTheDocument();
- });
- });
- it("confirm button Rendered", async () => {
- render();
- await waitFor(() => {
- const cancelBtn = screen.queryByText('ثبت');
- expect(cancelBtn).toBeInTheDocument();
- });
- });
- });
- describe("Form Submission", () => {
- it('Should enable the submit button when the inputs are valid', async () => {
- render();
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const passwordInput = screen.queryByLabelText('رمز عبور');
- const positionInput = screen.queryByLabelText('سمت');
-
- selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
- selectDropdownItem(screen, "option-opener-role", "ادمین");
- selectDropdownItem(screen, "option-opener-gender", "مرد");
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'emailTest');
- setInputValue(screen, phoneNumberInput, 'phoneNumberTest');
- setInputValue(screen, telephoneIdInput, 'telephoneIdTest');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, passwordInput, 'passwordTest');
- setInputValue(screen, positionInput, 'positionTest');
-
- await waitFor(() => {
- expect(submitButton).not.toBeDisabled();
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx
deleted file mode 100644
index 084da99..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/CreateContent/index.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import {Box, Button, Chip, DialogActions, DialogContent, Divider,} from "@mui/material";
-import * as Yup from "yup";
-import {useTranslations} from "next-intl";
-import {useFormik} from "formik";
-import useRequest from "@/lib/app/hooks/useRequest";
-import {ADD_EXPERT} from "@/core/data/apiRoutes";
-import PersonalInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/PersonalInfo";
-import UserInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/UserInfo";
-import RestInfo from "@/components/dashboard/expert-management/Form/CreateForm/CreateContent/RestInfo";
-
-const CreateContent = ({setOpenCreateDialog, mutate}) => {
- const t = useTranslations();
- const requestServer = useRequest()
-
- const validationSchema = Yup.object().shape({
- full_name: Yup.string().required(t("ExpertMangement.error_message_full_name")),
- username: Yup.string().required(t("ExpertMangement.error_message_username")),
- 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")),
- gender: Yup.string().required(t("ExpertMangement.error_message_gender")),
- national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
- password: Yup.string()
- .required(t("ExpertMangement.error_message_password"))
- .matches(
- /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
- t("ExpertMangement.error_message_password_regex")
- ),
- position: Yup.string().required(t("ExpertMangement.error_message_position")),
- province_id: Yup.string().required(t("ExpertMangement.error_message_province_id")),
- roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
- });
-
- const formik = useFormik({
- initialValues: {
- full_name: "",
- username: "",
- email: "",
- phone_number: "",
- telephone_id: "",
- gender: "",
- national_id: "",
- password: "",
- position: "",
- province_id: "",
- roles: ""
- },
- validationSchema,
- onSubmit: (values, {setSubmitting}) => {
- const formData = new FormData();
- formData.append("full_name", values.full_name);
- formData.append("national_id", values.national_id);
- formData.append("phone_number", values.phone_number);
- formData.append("telephone_id", values.telephone_id);
- formData.append("gender", values.gender);
- formData.append("email", values.email);
- formData.append("username", values.username);
- formData.append("password", values.password);
- formData.append("province_id", values.province_id);
- formData.append("position", values.position);
- formData.append("roles", values.roles);
-
- requestServer(`${ADD_EXPERT}`, 'post', {auth: true, data: formData})
- .then((response) => {
- setOpenCreateDialog(false)
- mutate()
- }).catch(() => {
- }).finally(() => {
- setSubmitting(false);
- });
- },
- });
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default CreateContent
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js
deleted file mode 100644
index dda7f82..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
-import React from 'react';
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import CreateForm from "../../CreateForm";
-
-function selectDropdownItem(screen, openerTestId, itemText) {
- const opener = screen.getByTestId(openerTestId);
- fireEvent.mouseDown(opener);
- const selectItem = screen.queryByText(itemText);
- fireEvent.click(selectItem);
-}
-
-function setInputValue(screen, inputElement, value) {
- fireEvent.change(inputElement, {target: {value}});
-}
-
-describe("CreateForm Component From Expert Management", () => {
- describe("Rendering", () => {
- it("Create Button Rendered", () => {
- render();
- const CreateButton = screen.getByRole('button', {name: "افزودن"});
- expect(CreateButton).toBeInTheDocument();
- });
- it("Dialog Header Rendered", () => {
- render();
- const CreateDialogHeader = screen.queryByText("افزودن");
- expect(CreateDialogHeader).toBeInTheDocument();
- });
- });
- describe("Behavioral", () => {
- it("by Clicking Create Button Dialog Should Append To Document", async () => {
- render();
- const CreateButton = screen.getByRole('button', {name: "افزودن"});
- fireEvent.click(CreateButton);
- await act(() => {
- const CreateDialog = screen.getByRole('dialog', {name: "افزودن"})
- expect(CreateDialog).toBeInTheDocument();
- });
- });
- });
- describe("Form Submission", () => {
- it('Should request to api and if get success close dialog', async () => {
- render();
-
- const CreateButton = screen.getByRole('button', {name: "افزودن"});
- fireEvent.click(CreateButton);
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const passwordInput = screen.queryByLabelText('رمز عبور');
- const positionInput = screen.queryByLabelText('سمت');
-
- selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
- selectDropdownItem(screen, "option-opener-role", "ادمین");
- selectDropdownItem(screen, "option-opener-gender", "مرد");
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'emailTest@gmail.com');
- setInputValue(screen, phoneNumberInput, '0914577458');
- setInputValue(screen, telephoneIdInput, '091');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, passwordInput, 'passwordTest12');
- setInputValue(screen, positionInput, 'positionTest');
-
- expect(submitButton).not.toBeDisabled();
- fireEvent.click(submitButton);
-
- await waitFor(() => {
- const dialogContent = screen.queryByTestId('create-dialog-content');
- expect(dialogContent).not.toBeInTheDocument();
- });
- });
- it('Should request to api and if get error keep previous data', async () => {
- render();
-
- const CreateButton = screen.getByRole('button', {name: "افزودن"});
- fireEvent.click(CreateButton);
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const passwordInput = screen.queryByLabelText('رمز عبور');
- const positionInput = screen.queryByLabelText('سمت');
- const provinceInput = screen.getByTestId("input-province-id")
- const roleInput = screen.getByTestId("input-role-id")
- const genderInput = screen.getByTestId("input-gender")
-
- selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
- selectDropdownItem(screen, "option-opener-role", "ادمین");
- selectDropdownItem(screen, "option-opener-gender", "مرد");
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'emailTest@gmail.com');
- setInputValue(screen, phoneNumberInput, '0914577458');
- setInputValue(screen, telephoneIdInput, '091');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, passwordInput, 'passwordTest12');
- setInputValue(screen, positionInput, 'positionTest');
-
- expect(submitButton).not.toBeDisabled();
- await fireEvent.click(submitButton);
-
- await waitFor(() => {
- expect(nameInput).toHaveValue('nameTest');
- expect(usernameInput).toHaveValue('usernameTest');
- expect(emailInput).toHaveValue('emailTest@gmail.com');
- expect(phoneNumberInput).toHaveValue('0914577458');
- expect(telephoneIdInput).toHaveValue('091');
- expect(nationalIdInput).toHaveValue('nationalIdTest');
- expect(passwordInput).toHaveValue('passwordTest12');
- expect(positionInput).toHaveValue('positionTest');
- expect(provinceInput).toHaveValue('1');
- expect(roleInput).toHaveValue('1');
- expect(genderInput).toHaveValue('male');
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/CreateForm/index.jsx b/src/components/dashboard/expert-management/Form/CreateForm/index.jsx
deleted file mode 100644
index 92f822f..0000000
--- a/src/components/dashboard/expert-management/Form/CreateForm/index.jsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import {Button, Dialog, DialogTitle, Stack, Tooltip} from "@mui/material";
-import {useTranslations} from "next-intl";
-import DataSaverOnIcon from "@mui/icons-material/DataSaverOn";
-import {useState} from "react";
-import CreateContent from "./CreateContent";
-
-const Create = ({mutate}) => {
- const t = useTranslations();
- const [openCreateDialog, setOpenCreateDialog] = useState(false);
-
- return (
- <>
-
-
-
-
-
-
- >
- )
-}
-
-export default Create
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/DeleteForm/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/DeleteForm/__tests__/index.test.js
deleted file mode 100644
index f2e52b0..0000000
--- a/src/components/dashboard/expert-management/Form/DeleteForm/__tests__/index.test.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import React from "react";
-import DeleteForm from "@/components/dashboard/expert-management/Form/DeleteForm";
-
-describe("CreateForm Component From Expert Management", () => {
- describe("Rendering", () => {
- it("Delete Expert Button And Tooltip Rendered", () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- expect(DeleteButton).toBeInTheDocument();
- });
- it("Delete Dialog Rendered", () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- const DeleteDialogHeader = screen.queryByText("حذف کارشناس");
- expect(DeleteDialogHeader).toBeInTheDocument();
- });
- it("Delete Dialog Text Rendered", () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- const DeleteDialogText = screen.queryByText("آیا از انجام این عملیات اطمینان دارید؟");
- expect(DeleteDialogText).toBeInTheDocument();
- });
- it("Delete Dialog Delete Button Rendered", () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- const DeleteButtonDialog = screen.getByRole('button', {name: "حذف"});
- expect(DeleteButtonDialog).toBeInTheDocument();
- });
- it("Delete Dialog Cancel Button Rendered", () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- const CancelButtonDialog = screen.getByRole('button', {name: "بستن"});
- expect(CancelButtonDialog).toBeInTheDocument();
- });
- });
- describe("Behavioral", () => {
- it("By Clicking Delete Button Dialog Should Append To Document", async () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- await waitFor(() => {
- const DeleteDialog = screen.getByRole('dialog', {name: "حذف کارشناس"})
- expect(DeleteDialog).toBeInTheDocument();
- });
- });
- });
- describe("Form Submission", () => {
- it("By Clicking Delete Button Request To Api And Delete Item", async () => {
- render();
- const DeleteButton = screen.getByTestId('delete-button');
- fireEvent.click(DeleteButton);
- const DeleteButtonDialog = screen.getByRole('button', {name: "حذف"});
- fireEvent.click(DeleteButtonDialog);
- await waitFor(() => {
- const DeleteDialog = screen.queryByRole('dialog', {name: "حذف کارشناس"});
- expect(DeleteDialog).not.toBeInTheDocument();
- });
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/DeleteForm/index.jsx b/src/components/dashboard/expert-management/Form/DeleteForm/index.jsx
deleted file mode 100644
index 0d8e592..0000000
--- a/src/components/dashboard/expert-management/Form/DeleteForm/index.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import {
- Button,
- Dialog,
- DialogActions,
- DialogContent,
- DialogContentText,
- DialogTitle,
- IconButton,
- Tooltip
-} from "@mui/material";
-import DeleteIcon from '@mui/icons-material/Delete';
-import {useState} from "react";
-import {DELETE_EXPERT} from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-import {useTranslations} from "next-intl";
-
-const Delete = ({rowId, mutate}) => {
- const t = useTranslations();
- const requestServer = useRequest({auth: true});
- const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
- const [isSubmitting, setIsSubmitting] = useState(false);
-
- const handleDelete = () => {
- setIsSubmitting(true)
- requestServer(`${DELETE_EXPERT}/${rowId}`, 'DELETE')
- .then((response) => {
- setOpenDeleteDialog(false);
- mutate()
- })
- .catch(() => {
- })
- .finally(() => {
- setIsSubmitting(false)
- });
- };
-
- return (
- <>
-
- {
- setOpenDeleteDialog(true);
- }}
- >
-
-
-
-
- >
- );
-};
-export default Delete;
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/__tests__/index.test.js
deleted file mode 100644
index b8692d5..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/__tests__/index.test.js
+++ /dev/null
@@ -1,219 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-
-describe("PersonalInfo Component From Expert Management (update)", () => {
- describe("Rendering", () => {
- it("full_name TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const fullNameTextField = screen.queryByLabelText('نام کامل');
- expect(fullNameTextField).toBeInTheDocument();
- });
- });
- it("Email TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const emailTextField = screen.queryByLabelText('پست الکترونیک');
- expect(emailTextField).toBeInTheDocument();
- });
- });
- it("Phone Number TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
- expect(phoneNumberTextField).toBeInTheDocument();
- });
- });
- it("telephone id TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
- expect(telephoneIdTextField).toBeInTheDocument();
- });
- });
- it("National Id TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const nationalIdTextField = screen.queryByLabelText('کد ملی');
- expect(nationalIdTextField).toBeInTheDocument();
- });
- });
- it("Gender Select Box Rendered", async () => {
- render();
- await waitFor(() => {
- const genderSelectBox = screen.getByTestId('select-box');
- expect(genderSelectBox).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Name TextField Work Correctly", async () => {
- render();
- const nameTextField = screen.queryByLabelText('نام کامل');
- fireEvent.change(nameTextField, {target: {value: 'exampleName'}});
- await act(() => {
- expect(nameTextField).toHaveValue('exampleName');
- })
- });
- it("Email TextField Work Correctly", async () => {
- render();
- const emailTextField = screen.queryByLabelText('پست الکترونیک');
- fireEvent.change(emailTextField, {target: {value: 'exampleEmail'}});
- await act(() => {
- expect(emailTextField).toHaveValue('exampleEmail');
- })
- });
- it("Phone Number TextField Work Correctly", async () => {
- render();
- const phoneNumberTextField = screen.queryByLabelText('شماره همراه');
- fireEvent.change(phoneNumberTextField, {target: {value: 'examplePhoneNumber'}});
- await act(() => {
- expect(phoneNumberTextField).toHaveValue('examplePhoneNumber');
- })
- });
- it("Telephone Id TextField Work Correctly", async () => {
- render();
- const telephoneIdTextField = screen.queryByLabelText('کد تلفن');
- fireEvent.change(telephoneIdTextField, {target: {value: 'exampleTelephoneId'}});
- await act(() => {
- expect(telephoneIdTextField).toHaveValue('exampleTelephoneId');
- })
- });
- it("National Id TextField Work Correctly", async () => {
- render();
- const nationalIdTextField = screen.queryByLabelText('کد ملی');
- fireEvent.change(nationalIdTextField, {target: {value: 'exampleNationalId'}});
- await act(() => {
- expect(nationalIdTextField).toHaveValue('exampleNationalId');
- })
- });
- it("Gender Select Box Work Correctly", async () => {
- render();
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
-
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/index.jsx
deleted file mode 100644
index f92bf38..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/PersonalInfo/index.jsx
+++ /dev/null
@@ -1,128 +0,0 @@
-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 (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {t("ExpertMangement.text_field_gender")}
-
-
- {formik.touched.gender && formik.errors.gender ? formik.errors.gender : ""}
-
-
-
-
- )
-}
-export default PersonalInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/__tests__/index.test.js
deleted file mode 100644
index d6062c5..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/__tests__/index.test.js
+++ /dev/null
@@ -1,96 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("PositionAndRole Component From Expert Management (update)", () => {
- describe("Rendering", () => {
- it("Position TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const positionTextField = screen.queryByLabelText('سمت');
- expect(positionTextField).toBeInTheDocument();
- });
- });
- it("Role Select Box Rendered", async () => {
- render();
- const roleSelect = screen.getByTestId('select-box');
- await waitFor(() => {
- expect(roleSelect).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Position TextField Work Correctly", async () => {
- render();
- const positionTextField = screen.queryByLabelText('سمت');
- fireEvent.change(positionTextField, {target: {value: 'examplePosition'}});
- await waitFor(() => {
- expect(positionTextField).toHaveValue('examplePosition');
- })
- });
- it("Role Select Box Work Correctly", async () => {
- render();
- 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();
-
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/index.jsx
deleted file mode 100644
index 4fc402a..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole/index.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-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 (
-
-
-
-
-
-
- {t("ExpertMangement.text_field_roles")}
-
-
- {formik.touched.roles && formik.errors.roles ? formik.errors.roles : ""}
-
-
-
-
- )
-}
-export default PositionAndRole
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/__tests__/index.test.js
deleted file mode 100644
index d727188..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/__tests__/index.test.js
+++ /dev/null
@@ -1,71 +0,0 @@
-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 (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("Province Component From Expert Management (update)", () => {
- describe("Rendering", () => {
- it("Province Select Box Rendered", async () => {
- render();
- await waitFor(() => {
- const provinceSelectBox = screen.getByTestId('select-box');
- expect(provinceSelectBox).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Province Select Box Work Correctly", async () => {
- render();
- 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();
- 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')
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/index.jsx
deleted file mode 100644
index 763465e..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province/index.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-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 (
-
-
-
- {t("ExpertMangement.text_field_province_id")}
-
-
- {formik.touched.province_id && formik.errors.province_id ? formik.errors.province_id : ""}
-
-
-
-
- )
-}
-export default Province
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/index.jsx
deleted file mode 100644
index 36c1877..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/index.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import Province from "@/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/Province";
-import PositionAndRole
- from "@/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/RestInfo/PositionAndRole";
-
-const RestInfo = ({formik}) => {
- return (
- <>
-
-
- >
- )
-}
-export default RestInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/__tests__/index.test.js
deleted file mode 100644
index 3fd341d..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/__tests__/index.test.js
+++ /dev/null
@@ -1,62 +0,0 @@
-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")),
- });
- return (
- {
- }}
- >
- {formikProps => ()}
-
- );
-};
-
-describe("UserInfo Component From Expert Management (update)", () => {
- describe("Rendering", () => {
- it("UserName TextField Rendered", async () => {
- render();
- await waitFor(() => {
- const usernameTextField = screen.queryByLabelText('نام کاربری');
- expect(usernameTextField).toBeInTheDocument();
- });
- });
- });
- describe("Behavioral", () => {
- it("Username TextField Work Correctly", async () => {
- render();
- const usernameTextField = screen.queryByLabelText('نام کاربری');
- fireEvent.change(usernameTextField, {target: {value: 'exampleUsername'}});
- await act(() => {
- expect(usernameTextField).toHaveValue('exampleUsername');
- })
- });
- });
- describe("validation", () => {
- it('Should See Error When Username Input Is Empty', async () => {
- render();
-
- const usernameInput = screen.queryByLabelText('نام کاربری');
-
- fireEvent.change(usernameInput, {target: {value: ''}});
- fireEvent.blur(usernameInput);
-
- await waitFor(() => {
- expect(screen.queryByText("نام کاربری خود را وارد کنید")).toBeInTheDocument()
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/index.jsx
deleted file mode 100644
index d592ea5..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/UserInfo/index.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import {Grid, TextField} from "@mui/material";
-import {useTranslations} from "next-intl";
-
-const UserInfo = ({formik}) => {
- const t = useTranslations();
-
- return (
- <>
-
-
-
-
-
- >
- )
-}
-export default UserInfo
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/__tests__/index.test.js
deleted file mode 100644
index 765bc09..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/__tests__/index.test.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import React from 'react';
-import MockAppWithProviders from "../../../../../../../../mocks/AppWithProvider";
-import UpdateContent from "../../UpdateContent";
-
-const row = {
- original: {
- avatar: null,
- created_at: "2023-10-10T13:05:01.000000Z",
- email: "fisher.sigrid@yahoo.com",
- full_name: "Anibal Labadie",
- gender: "female",
- id: 85,
- national_id: "5944646138",
- phone_number: "09731311720",
- position: "boss1",
- province_fa: "اردبیل",
- province_id: 3,
- roles: [{
- created_at: "2023-10-10T13:03:18.000000Z",
- guard_name: "api",
- id: 2,
- name: "manager",
- name_fa: "مدیر"
- }],
- telephone_id: "tel-3110",
- updated_at: "2023-10-17T10:57:12.000000Z",
- username: "florence.kihn",
- }
-}
-
-function selectDropdownItem(screen, openerTestId, itemText) {
- const opener = screen.getByTestId(openerTestId);
- fireEvent.mouseDown(opener);
- const selectItem = screen.queryByText(itemText);
- fireEvent.click(selectItem);
-}
-
-function setInputValue(screen, inputElement, value) {
- fireEvent.change(inputElement, {target: {value}});
-}
-
-describe("UpdateContent Component From Expert Management (update)", () => {
- describe("Rendering", () => {
- it("close button Rendered", async () => {
- render();
- await waitFor(() => {
- const cancelBtn = screen.queryByText('بستن');
- expect(cancelBtn).toBeInTheDocument();
- });
- });
- it("confirm button Rendered", async () => {
- render();
- await waitFor(() => {
- const confirmBtn = screen.queryByText('ثبت');
- expect(confirmBtn).toBeInTheDocument();
- });
- });
- });
- describe("Form Submission", () => {
- it('Should enable the submit button when the inputs are valid', async () => {
- render();
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const positionInput = screen.queryByLabelText('سمت');
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'emailTest');
- setInputValue(screen, phoneNumberInput, 'phoneNumberTest');
- setInputValue(screen, telephoneIdInput, 'telephoneIdTest');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, positionInput, 'positionTest');
-
- await waitFor(() => {
- expect(submitButton).not.toBeDisabled();
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/index.jsx
deleted file mode 100644
index 1f482dc..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/UpdateContent/index.jsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import {Box, Button, Chip, DialogActions, DialogContent, Divider,} from "@mui/material";
-import * as Yup from "yup";
-import {useTranslations} from "next-intl";
-import {useFormik} from "formik";
-import useRequest from "@/lib/app/hooks/useRequest";
-import {UPDATE_EXPERT} from "@/core/data/apiRoutes";
-import PersonalInfo from "./PersonalInfo";
-import UserInfo from "./UserInfo";
-import RestInfo from "./RestInfo";
-
-const UpdateContent = ({row, mutate, setOpenUpdateDialog}) => {
- const t = useTranslations();
- const requestServer = useRequest()
-
- const validationSchema = Yup.object().shape({
- full_name: Yup.string().required(t("ExpertMangement.error_message_full_name")),
- username: Yup.string().required(t("ExpertMangement.error_message_username")),
- 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")),
- gender: Yup.string().required(t("ExpertMangement.error_message_gender")),
- national_id: Yup.string().required(t("ExpertMangement.error_message_national_id")),
- position: Yup.string().required(t("ExpertMangement.error_message_position")),
- province_id: Yup.string().required(t("ExpertMangement.error_message_province_id")),
- roles: Yup.string().required(t("ExpertMangement.error_message_roles"))
- });
-
- const formik = useFormik({
- initialValues: {
- full_name: row.original.full_name,
- username: row.original.username,
- email: row.original.email,
- phone_number: row.original.phone_number,
- telephone_id: row.original.telephone_id,
- gender: row.original.gender,
- national_id: row.original.national_id,
- position: row.original.position,
- province_id: row.original.province_id,
- roles: row.original.roles[0]?.id
- },
- validationSchema,
- onSubmit: (values, {setSubmitting}) => {
- const formData = new FormData();
- formData.append("full_name", values.full_name);
- formData.append("national_id", values.national_id);
- formData.append("phone_number", values.phone_number);
- formData.append("telephone_id", values.telephone_id);
- formData.append("gender", values.gender);
- formData.append("email", values.email);
- formData.append("username", values.username);
- formData.append("province_id", values.province_id);
- formData.append("position", values.position);
- formData.append("roles", values.roles);
-
- requestServer(`${UPDATE_EXPERT}/${row.original.id}`, 'post', {auth: true, data: formData})
- .then((response) => {
- setOpenUpdateDialog(false)
- mutate()
- }).catch(() => {
- }).finally(() => {
- setSubmitting(false);
- });
- },
- });
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default UpdateContent
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/UpdateForm/__tests__/index.test.js
deleted file mode 100644
index f824d6d..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/__tests__/index.test.js
+++ /dev/null
@@ -1,147 +0,0 @@
-import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
-import React from 'react';
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import UpdateForm from "../../UpdateForm";
-
-const row = {
- original: {
- avatar: null,
- created_at: "2023-10-10T13:05:01.000000Z",
- email: "fisher.sigrid@yahoo.com",
- full_name: "Anibal Labadie",
- gender: "female",
- id: 85,
- national_id: "5944646138",
- phone_number: "09731311720",
- position: "boss1",
- province_fa: "اردبیل",
- province_id: 3,
- roles: [{
- created_at: "2023-10-10T13:03:18.000000Z",
- guard_name: "api",
- id: 2,
- name: "manager",
- name_fa: "مدیر"
- }],
- telephone_id: "tel-3110",
- updated_at: "2023-10-17T10:57:12.000000Z",
- username: "florence.kihn",
- }
-}
-
-function selectDropdownItem(screen, openerTestId, itemText) {
- const opener = screen.getByTestId(openerTestId);
- fireEvent.mouseDown(opener);
- const selectItem = screen.queryByText(itemText);
- fireEvent.click(selectItem);
-}
-
-function setInputValue(screen, inputElement, value) {
- fireEvent.change(inputElement, {target: {value}});
-}
-
-describe("CreateForm Component From Expert Management", () => {
- describe("Rendering", () => {
- it("Update Expert Button Rendered", () => {
- render();
- const UpdateButton = screen.getByTestId('update-button');
- expect(UpdateButton).toBeInTheDocument();
- });
- });
- describe("Behavioral", () => {
- it("by Clicking Update Button Dialog Should Append To Document", async () => {
- render();
- const UpdateButton = screen.getByTestId('update-button');
- fireEvent.click(UpdateButton);
- await act(() => {
- const UpdateDialog = screen.getByRole('dialog', {name: "ویرایش کارشناس"})
- expect(UpdateDialog).toBeInTheDocument();
- });
- });
- });
- describe("Form Submission", () => {
- it('Should request to api and if get success close dialog', async () => {
- render();
-
- const UpdateButton = screen.getByTestId('update-button');
- fireEvent.click(UpdateButton);
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const positionInput = screen.queryByLabelText('سمت');
-
- selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
- selectDropdownItem(screen, "option-opener-role", "ادمین");
- selectDropdownItem(screen, "option-opener-gender", "مرد");
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'email@gmail.com');
- setInputValue(screen, phoneNumberInput, '0914577458');
- setInputValue(screen, telephoneIdInput, '091');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, positionInput, 'positionTest');
-
- expect(submitButton).not.toBeDisabled();
- fireEvent.click(submitButton);
-
- await waitFor(() => {
- const dialogContent = screen.queryByTestId('update-dialog-content');
- expect(dialogContent).not.toBeInTheDocument();
- });
- });
- it('Should request to api and if get error keep previous data', async () => {
- render();
-
- const UpdateButton = screen.getByTestId('update-button');
- fireEvent.click(UpdateButton);
-
- const submitButton = screen.queryByText('ثبت');
-
- const nameInput = screen.queryByLabelText('نام کامل');
- const usernameInput = screen.queryByLabelText('نام کاربری');
- const emailInput = screen.queryByLabelText('پست الکترونیک');
- const phoneNumberInput = screen.queryByLabelText('شماره همراه');
- const telephoneIdInput = screen.queryByLabelText('کد تلفن');
- const nationalIdInput = screen.queryByLabelText('کد ملی');
- const positionInput = screen.queryByLabelText('سمت');
- const provinceInput = screen.getByTestId("input-province-id")
- const roleInput = screen.getByTestId("input-role-id")
- const genderInput = screen.getByTestId("input-gender")
-
- selectDropdownItem(screen, "option-opener-province", "آذربایجان شرقی");
- selectDropdownItem(screen, "option-opener-role", "ادمین");
- selectDropdownItem(screen, "option-opener-gender", "مرد");
-
- setInputValue(screen, nameInput, 'nameTest');
- setInputValue(screen, usernameInput, 'usernameTest');
- setInputValue(screen, emailInput, 'emailTest@gmail.com');
- setInputValue(screen, phoneNumberInput, '0914577458');
- setInputValue(screen, telephoneIdInput, '091');
- setInputValue(screen, nationalIdInput, 'nationalIdTest');
- setInputValue(screen, positionInput, 'positionTest');
-
- expect(submitButton).not.toBeDisabled();
- await fireEvent.click(submitButton);
-
- await waitFor(() => {
- expect(nameInput).toHaveValue('nameTest');
- expect(usernameInput).toHaveValue('usernameTest');
- expect(emailInput).toHaveValue('emailTest@gmail.com');
- expect(phoneNumberInput).toHaveValue('0914577458');
- expect(telephoneIdInput).toHaveValue('091');
- expect(nationalIdInput).toHaveValue('nationalIdTest');
- expect(positionInput).toHaveValue('positionTest');
- expect(provinceInput).toHaveValue('1');
- expect(roleInput).toHaveValue('1');
- expect(genderInput).toHaveValue('male');
- });
- });
- })
-});
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/Form/UpdateForm/index.jsx b/src/components/dashboard/expert-management/Form/UpdateForm/index.jsx
deleted file mode 100644
index 27fae5c..0000000
--- a/src/components/dashboard/expert-management/Form/UpdateForm/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Dialog, DialogTitle, IconButton, Tooltip} from "@mui/material";
-import EditIcon from '@mui/icons-material/Edit';
-import {useState} from "react";
-import UpdateContent from "./UpdateContent";
-
-
-const Update = ({row, mutate}) => {
- const t = useTranslations();
- const [openUpdateDialog, setOpenUpdateDialog] = useState(false);
-
- return (
- <>
-
- {
- setOpenUpdateDialog(true)
- }}
- >
-
-
-
-
- >
- );
-};
-export default Update;
\ No newline at end of file
diff --git a/src/components/dashboard/expert-management/TableRowActions.jsx b/src/components/dashboard/expert-management/TableRowActions.jsx
deleted file mode 100644
index 91e778e..0000000
--- a/src/components/dashboard/expert-management/TableRowActions.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import {Box} from "@mui/material";
-import Update from "./Form/UpdateForm"
-import Delete from "./Form/DeleteForm";
-
-const TableRowActions = ({row, mutate}) => {
- return (
-
-
- {/**/}
-
-
- );
-};
-
-export default TableRowActions;
diff --git a/src/components/dashboard/expert-management/TableToolbar.jsx b/src/components/dashboard/expert-management/TableToolbar.jsx
deleted file mode 100644
index 24f26f7..0000000
--- a/src/components/dashboard/expert-management/TableToolbar.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import {useTranslations} from "next-intl";
-import Create from "./Form/CreateForm";
-import {Box} from "@mui/material";
-
-function TableToolbar({mutate}) {
- const t = useTranslations();
- return (
-
-
-
- );
-}
-
-export default TableToolbar;
diff --git a/src/components/dashboard/expert-management/index.jsx b/src/components/dashboard/expert-management/index.jsx
deleted file mode 100644
index 632d89b..0000000
--- a/src/components/dashboard/expert-management/index.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import DashboardLayouts from "@/layouts/DashboardLayout";
-import ExpertManagementDataTable from "@/components/dashboard/expert-management/DataTable";
-
-function DashboardExpertManagementComponent() {
- return (
-
-
-
- );
-}
-
-export default DashboardExpertManagementComponent;
diff --git a/src/components/dashboard/first/index.jsx b/src/components/dashboard/first/index.jsx
deleted file mode 100644
index 841d677..0000000
--- a/src/components/dashboard/first/index.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import DashboardLayout from "@/layouts/DashboardLayout";
-
-const DashboardFirstComponent = () => {
- return ;
-};
-
-export default DashboardFirstComponent;
diff --git a/src/components/dashboard/role-management/Form/CreateForm/CreateContent.jsx b/src/components/dashboard/role-management/Form/CreateForm/CreateContent.jsx
deleted file mode 100644
index d06659b..0000000
--- a/src/components/dashboard/role-management/Form/CreateForm/CreateContent.jsx
+++ /dev/null
@@ -1,153 +0,0 @@
-import {
- Button,
- Checkbox,
- CircularProgress,
- DialogActions,
- DialogContent,
- DialogTitle,
- FormControl,
- FormControlLabel,
- FormHelperText,
- FormLabel,
- Grid,
- Stack,
- TextField,
- Typography
-} from "@mui/material";
-import {useTranslations} from "next-intl";
-import useRequest from "@/lib/app/hooks/useRequest";
-import * as Yup from "yup";
-import {useFormik} from "formik";
-import {ADD_ROLE} from "@/core/data/apiRoutes";
-import usePermissions from "@/lib/app/hooks/usePermissions";
-
-const CreateContent = ({mutate, setOpenConfirmDialog}) => {
- const t = useTranslations();
- const requestServer = useRequest({auth: true})
- const {permissions_list, isLoading} = usePermissions()
- const validationSchema = Yup.object().shape({
- name_en: Yup.string().required(t("AddDialog.name_en_error")),
- name_fa: Yup.string().required(t("AddDialog.name_fa_error")),
- permissions: Yup.array().min(1, t("AddDialog.permission_min_error")).required(t("AddDialog.permission")),
- });
- const formik = useFormik({
- initialValues: {
- name_en: "",
- name_fa: "",
- permissions: [],
- }, validationSchema, onSubmit: (values, {setSubmitting}) => {
- const formData = new FormData();
- formData.append("name", values.name_en);
- formData.append("name_fa", values.name_fa);
- for (let i = 0; i < values.permissions.length; i++) {
- formData.append(`permissions[${i}]`, values.permissions[i]);
- }
-
- requestServer(ADD_ROLE, 'post', {
- data: formData,
- }).then(() => {
- setOpenConfirmDialog(false)
- mutate()
- update_notification()
- }).catch(() => {
- }).finally(() => {
- setSubmitting(false);
- });
- },
- });
-
- return (
- <>
- {t("AddDialog.add")}
-
-
-
-
-
-
-
- {t("AddDialog.permission")}
-
- {formik.touched.permissions && formik.errors.permissions}
- {isLoading ?
-
-
- {t("AddDialog.loading_permissions_list")}
-
- : (
-
- <>
- {permissions_list.map((permission) => (
-
- {
- if (e.target.checked) {
- formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
- } else {
- formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
- }
- }}
- />
- }
- label={permission.name_fa}
- />
-
- ))}
- >
-
- )
- }
-
-
-
-
-
-
-
-
-
- >
- )
-}
-export default CreateContent
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/CreateForm/__test__/CreateContent.test.js b/src/components/dashboard/role-management/Form/CreateForm/__test__/CreateContent.test.js
deleted file mode 100644
index 610e224..0000000
--- a/src/components/dashboard/role-management/Form/CreateForm/__test__/CreateContent.test.js
+++ /dev/null
@@ -1,167 +0,0 @@
-import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import CreateContent from "@/components/dashboard/role-management/Form/CreateForm/CreateContent";
-
-describe("Create Content component from Create Form Component in Role Management Component",()=>{
- describe("Rendering", ()=>{
- it('should see AddDialog text in the top ', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByText("افزودن")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see name_en text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByLabelText("نام انگلیسی")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see name_fa text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByLabelText("نام فارسی")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see name_fa text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByLabelText("نام فارسی")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- })
- describe("Behavior",()=>{
- it('should see what fill in the name_en input', async () => {
- render(
-
-
-
- )
- const nameEnglishInput = screen.getByLabelText('نام انگلیسی');
-
- fireEvent.change(nameEnglishInput, {target: {value: 'testuser'}});
- await act(()=>{
- // Simulate user input
- expect(nameEnglishInput).toHaveValue('testuser');
- })
- });
- it('should see what fill in the name_fa input', async () => {
- render(
-
-
-
- )
- const nameFarsiInput = screen.getByLabelText('نام فارسی');
-
- fireEvent.change(nameFarsiInput, {target: {value: 'testuser'}});
- await act(()=>{
- // Simulate user input
- expect(nameFarsiInput).toHaveValue('testuser');
- })
- });
- it('should return permissions_list', async () => {
- render(
-
-
-
- )
- const checkboxElement = await screen.findAllByTestId("PermissionList-checkbox")
- expect(checkboxElement).toHaveLength(2)
- });
- it('should get checked if permission list item get clicked', async () => {
- render(
-
-
-
- )
- const checkboxElement = screen.getByLabelText("مدیریت کارتابل رییس اداره مسافری استان")
-
- await waitFor(()=>{
- expect(checkboxElement).not.toBeChecked();
- })
-
- fireEvent.click(checkboxElement);
-
- await waitFor(()=>{
- expect(checkboxElement).toBeChecked();
- })
- });
- })
- describe("Validation",()=>{
- it('should see error text when name_fa input is empty', async () => {
- render(
-
-
-
- )
- const name_faInput = screen.getByLabelText("نام فارسی")
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).not.toBeInTheDocument()
- fireEvent.blur(name_faInput);
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).toBeInTheDocument()
- })
- fireEvent.change(name_faInput, {target : {value : "نام فارسی"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).not.toBeInTheDocument()
- })
- })
- it('should see error text when name_en input is empty', async () => {
- render(
-
-
-
- )
- const name_enInput = screen.getByLabelText("نام انگلیسی")
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).not.toBeInTheDocument()
- fireEvent.blur(name_enInput);
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).toBeInTheDocument()
- })
- fireEvent.change(name_enInput, {target : {value : "english name"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).not.toBeInTheDocument()
- })
- })
- it('should see errors when click on submit button and field not completed', async () => {
- render(
-
-
-
- )
- const submitButtonElement = screen.queryByText("ثبت")
- fireEvent.click(submitButtonElement)
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).toBeInTheDocument()
- })
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).toBeInTheDocument()
- })
- await waitFor(()=>{
- expect(screen.queryByText("حداقل باید یک دسترسی انتخاب شود")).toBeInTheDocument()
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/CreateForm/__test__/index.test.js b/src/components/dashboard/role-management/Form/CreateForm/__test__/index.test.js
deleted file mode 100644
index 7bc9db2..0000000
--- a/src/components/dashboard/role-management/Form/CreateForm/__test__/index.test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import {fireEvent, queryByText, render, screen, waitFor} from "@testing-library/react";
-import CreateForm from "@/components/dashboard/role-management/Form/CreateForm";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-
-describe("Create Form Component from Role Management Component",()=>{
- describe("Rendering",()=>{
-
- it('should see Dialog text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByText("افزودن")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
-
- it('should see Tooltip text when mouse over', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.getByText("افزودن");
- fireEvent.mouseOver(buttonElement);
- const tooltipTextElement = screen.getByText("افزودن");
- await waitFor(()=>{
- expect(tooltipTextElement).toBeInTheDocument()
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/CreateForm/index.jsx b/src/components/dashboard/role-management/Form/CreateForm/index.jsx
deleted file mode 100644
index 455d9a2..0000000
--- a/src/components/dashboard/role-management/Form/CreateForm/index.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import {Button, Dialog, Stack, Tooltip} from "@mui/material";
-import DataSaverOnIcon from "@mui/icons-material/DataSaverOn";
-import {useTranslations} from "next-intl";
-import {useState} from "react";
-import CreateContent from "./CreateContent";
-
-const CreateForm = ({mutate}) => {
- const t = useTranslations();
- const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
-
- return (
-
-
-
-
-
-
- )
-}
-export default CreateForm
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/DeleteForm/DeleteContent.jsx b/src/components/dashboard/role-management/Form/DeleteForm/DeleteContent.jsx
deleted file mode 100644
index f1580ce..0000000
--- a/src/components/dashboard/role-management/Form/DeleteForm/DeleteContent.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import {Button, DialogActions, DialogContent, DialogTitle, Typography} from "@mui/material";
-import {DELETE_ROLE} from "@/core/data/apiRoutes";
-import {useState} from "react";
-import useRequest from "@/lib/app/hooks/useRequest";
-import useNotification from "@/lib/app/hooks/useNotification";
-import {useTranslations} from "next-intl";
-
-const DeleteContent = ({rowId, mutate, setOpenConfirmDialog}) => {
- const t = useTranslations();
- const [isSubmitting, setIsSubmitting] = useState(false)
- const requestServer = useRequest({auth: true})
- const {update_notification} = useNotification()
- const handleSubmit = () => {
- setIsSubmitting(true)
- requestServer(`${DELETE_ROLE}/${rowId}`, 'delete').then((response) => {
- mutate()
- update_notification()
- }).catch(() => {
- }).finally(() => {
- setIsSubmitting(false)
- });
- }
- return (
- <>
- {t("DeleteDialog.delete")}
-
- {t("DeleteDialog.typography")}
-
-
-
-
-
- >
- )
-}
-export default DeleteContent
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/DeleteForm/__test__/DeleteContent.test.js b/src/components/dashboard/role-management/Form/DeleteForm/__test__/DeleteContent.test.js
deleted file mode 100644
index 7258e10..0000000
--- a/src/components/dashboard/role-management/Form/DeleteForm/__test__/DeleteContent.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import {act, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import DeleteContent from "@/components/dashboard/role-management/Form/DeleteForm/DeleteContent";
-import UpdateContent from "@/components/dashboard/role-management/Form/UpdateForm/UpdateContent";
-
-describe("Create Content component from Create Form Component in Role Management Component", () => {
- describe("Rendering", () => {
- it('should see DeleteDialog text in the top ', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByText("حذف")
- await waitFor(() => {
- expect(textElement).toBeInTheDocument()
- })
- })
- it('should see DeleteDialog text content ', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByText("آیا از حدف این مورد اطمینان دارید ؟")
- await waitFor(() => {
- expect(textElement).toBeInTheDocument()
- })
- })
- it('should see delete text in the delete button ', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.queryByText("حذف کردن")
- await waitFor(() => {
- expect(buttonElement).toBeInTheDocument()
- })
- });
- it('should see cancel text in the cancel button ', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.queryByText("انصراف")
- await waitFor(() => {
- expect(buttonElement).toBeInTheDocument()
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/DeleteForm/__test__/index.test.js b/src/components/dashboard/role-management/Form/DeleteForm/__test__/index.test.js
deleted file mode 100644
index d8eaaa2..0000000
--- a/src/components/dashboard/role-management/Form/DeleteForm/__test__/index.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import DeleteForm from "@/components/dashboard/role-management/Form/DeleteForm";
-import UpdateForm from "@/components/dashboard/role-management/Form/UpdateForm";
-
-describe("Create Form Component from Role Management Component",()=> {
- describe("Rendering", () => {
- it('should see Dialog text when mouse is over', async () => {
- render(
-
-
-
- )
- const textElement = screen.getByTestId("dialog_tooltip")
- fireEvent.mouseOver(textElement)
- await waitFor(()=>{
- expect(screen.getByText("حذف")).toBeInTheDocument();
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/DeleteForm/index.jsx b/src/components/dashboard/role-management/Form/DeleteForm/index.jsx
deleted file mode 100644
index 4ff70bd..0000000
--- a/src/components/dashboard/role-management/Form/DeleteForm/index.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import {useTranslations} from "next-intl";
-import {useState} from "react";
-import {Dialog, IconButton, Tooltip} from "@mui/material";
-import DeleteIcon from '@mui/icons-material/Delete';
-import DeleteContent from "@/components/dashboard/role-management/Form/DeleteForm/DeleteContent";
-
-const DeleteForm = ({rowId, mutate}) => {
- const t = useTranslations();
- const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
-
-
- return (
- <>
-
- {
- setOpenConfirmDialog(true)
- }}
- >
-
-
-
-
- >
- );
-};
-export default DeleteForm;
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/UpdateForm/UpdateContent.jsx b/src/components/dashboard/role-management/Form/UpdateForm/UpdateContent.jsx
deleted file mode 100644
index 3fee10a..0000000
--- a/src/components/dashboard/role-management/Form/UpdateForm/UpdateContent.jsx
+++ /dev/null
@@ -1,153 +0,0 @@
-import {
- Button,
- Checkbox,
- CircularProgress,
- DialogActions,
- DialogContent,
- DialogTitle,
- FormControl,
- FormControlLabel,
- FormHelperText,
- FormLabel,
- Grid,
- Stack,
- TextField,
- Typography
-} from "@mui/material";
-import {useFormik} from "formik";
-import {UPDATE_ROLE} from "@/core/data/apiRoutes";
-import * as Yup from "yup";
-import usePermissions from "@/lib/app/hooks/usePermissions";
-import useNotification from "@/lib/app/hooks/useNotification";
-import useRequest from "@/lib/app/hooks/useRequest";
-import {useTranslations} from "next-intl";
-
-const UpdateContent = ({mutate, row, setOpenConfirmDialog}) => {
- const t = useTranslations();
- const requestServer = useRequest({auth: true})
- const {update_notification} = useNotification()
- const {permissions_list, isLoading} = usePermissions()
-
- const validationSchema = Yup.object().shape({
- name_en: Yup.string().required(t("UpdateDialog.name_en_error")),
- name_fa: Yup.string().required(t("UpdateDialog.name_fa_error")),
- permissions: Yup.array().min(1, t("UpdateDialog.permission_min_error")).required(t("UpdateDialog.permission")),
- });
-
- const formik = useFormik({
- initialValues: {
- name_en: row.getValue("name"),
- name_fa: row.getValue("name_fa"),
- permissions: row.original.permissions.map((obj) => obj.id),
- }, validationSchema, onSubmit: (values, {setSubmitting}) => {
- const formData = new FormData();
- formData.append("name", values.name_en);
- formData.append("name_fa", values.name_fa);
- for (let i = 0; i < values.permissions.length; i++) {
- formData.append(`permissions[${i}]`, values.permissions[i]);
- }
-
- requestServer(`${UPDATE_ROLE}/${row.getValue("id")}`, 'post', {
- data: formData,
- }).then((response) => {
- setOpenConfirmDialog(false)
- mutate()
- update_notification()
- }).catch(() => {
- }).finally(() => {
- setSubmitting(false);
- });
- },
- });
-
- return (
- <>
- {t("UpdateDialog.update")}
-
-
-
-
-
-
-
- {t("UpdateDialog.permission")}
-
- {formik.touched.permissions && formik.errors.permissions}
- {isLoading ?
-
-
- {t("UpdateDialog.loading_permissions_list")}
-
- : (
-
- <>
- {permissions_list.map((permission) => (
-
- {
- if (e.target.checked) {
- formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
- } else {
- formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
- }
- }}
- />
- }
- label={permission.name_fa}
- />
-
- ))}
- >
-
- )}
-
-
-
-
-
-
-
-
-
- >
- )
-}
-export default UpdateContent
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/UpdateForm/__test__/UpdateContent.test.js b/src/components/dashboard/role-management/Form/UpdateForm/__test__/UpdateContent.test.js
deleted file mode 100644
index caaa470..0000000
--- a/src/components/dashboard/role-management/Form/UpdateForm/__test__/UpdateContent.test.js
+++ /dev/null
@@ -1,209 +0,0 @@
-import {act, fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import UpdateContent from "@/components/dashboard/role-management/Form/UpdateForm/UpdateContent";
-const row = {
- id : 0,
- getValue : name => {
- if (name === "name") {
- return "manage_passenger_office_navgan";
- }
- else if (name === "name_fa") {
- return "مدیریت کارتابل رییس اداره مسافری استان";
- }
- },
- original : {
- permissions : [
- {
- id: 1,
- name: "manage_passenger_office_navgan",
- name_fa: "مدیریت کارتابل رییس اداره مسافری استان"
- },
- {
- id: 2,
- name: "manage_passenger_office_navgan",
- name_fa: "مدیریت کارتابل رییس اداره مسافری استان"
- }
- ]
- }
-}
-
-describe("Create Content component from Create Form Component in Role Management Component",()=>{
- describe("Rendering", ()=>{
- it('should see AddDialog text in the top ', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByText("ویرایش")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see name_en text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByLabelText("نام انگلیسی")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see name_fa text', async () => {
- render(
-
-
-
- )
- const textElement = screen.queryByLabelText("نام فارسی")
- await waitFor(()=>{
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see update text in the submit button ', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.queryByText("ثبت")
- await waitFor(()=>{
- expect(buttonElement).toBeInTheDocument()
- })
- });
- it('should see cancel text in the cancel button ', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.queryByText("بستن")
- await waitFor(()=>{
- expect(buttonElement).toBeInTheDocument()
- })
- });
- })
-
- describe("Behavior", ()=>{
- it('should see what fill in the name_en input', async () => {
- render(
-
-
-
- )
- const nameEnglishInput = screen.getByLabelText('نام انگلیسی');
-
- fireEvent.change(nameEnglishInput, {target: {value: 'testuser'}});
- await waitFor(()=>{
- // Simulate user input
- expect(nameEnglishInput).toHaveValue('testuser');
- })
- });
- it('should see what fill in the name_fa input', async () => {
- render(
-
-
-
- )
- const nameFarsiInput = screen.getByLabelText('نام فارسی');
-
- fireEvent.change(nameFarsiInput, {target: {value: 'testuser'}});
- await waitFor(()=>{
- // Simulate user input
- expect(nameFarsiInput).toHaveValue('testuser');
- })
- });
- it('should return permissions_list', async () => {
- render(
-
-
-
- )
- const checkboxElement = await screen.findAllByTestId("PermissionList-checkbox")
- await waitFor(()=>{
- expect(checkboxElement).toHaveLength(2)
- })
- });
- it('should see the value of the name_en that pass to input value', async () => {
- render(
-
-
-
- )
- const name_enElement = screen.getByLabelText("نام انگلیسی")
- await waitFor(()=>{
- expect(name_enElement).toHaveValue("manage_passenger_office_navgan")
- })
- });
- it('should see the value of the name_fa that pass to input value', async () => {
- render(
-
-
-
- )
- const name_enElement = screen.getByLabelText("نام فارسی")
- await waitFor(()=>{
- expect(name_enElement).toHaveValue("مدیریت کارتابل رییس اداره مسافری استان")
- })
- });
- it('should get checked if the id exists in permission lists', async () => {
- render(
-
-
-
- )
- const checkboxElement = screen.getByLabelText("مدیریت کارتابل رییس اداره مسافری استان")
- await waitFor(()=>{
- expect(checkboxElement).toBeChecked();
- })
-
- });
- })
- describe("Validation", ()=>{
- it('should see error text when name_fa input is empty', async () => {
- render(
-
-
-
- )
- const name_faInput = screen.getByLabelText("نام فارسی")
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).not.toBeInTheDocument()
- fireEvent.change(name_faInput, {target : {value : ''}});
-
- fireEvent.blur(name_faInput)
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).toBeInTheDocument()
- })
- fireEvent.change(name_faInput, {target : {value : "نام فارسی"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام فارسی الزامیست")).not.toBeInTheDocument()
- })
- })
- it('should see error text when name_en input is empty', async () => {
- render(
-
-
-
- )
- const name_enInput = screen.getByLabelText("نام انگلیسی")
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).not.toBeInTheDocument()
-
- fireEvent.change(name_enInput, {target : {value : null}});
- fireEvent.blur(name_enInput)
-
- await waitFor(()=>{
-
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).toBeInTheDocument()
- })
- fireEvent.change(name_enInput, {target : {value : "english name"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام انگلیسی الزامیست")).not.toBeInTheDocument()
- })
- })
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/UpdateForm/__test__/index.test.js b/src/components/dashboard/role-management/Form/UpdateForm/__test__/index.test.js
deleted file mode 100644
index 2a0ee82..0000000
--- a/src/components/dashboard/role-management/Form/UpdateForm/__test__/index.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../mocks/AppWithProvider";
-import UpdateContent from "@/components/dashboard/role-management/Form/UpdateForm/UpdateContent";
-import UpdateForm from "@/components/dashboard/role-management/Form/UpdateForm";
-import userEvent from "@testing-library/user-event";
-
-describe("Create Form Component from Role Management Component",()=>{
- describe("Rendering",()=>{
- it('should see Tooltip text when mouse over', async () => {
- render(
-
-
-
- )
- const buttonElement = screen.getByTestId("dialog_tooltip");
- fireEvent.mouseOver(buttonElement);
- await waitFor(()=>{
- expect(screen.queryByText("ویرایش")).toBeVisible();
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/Form/UpdateForm/index.jsx b/src/components/dashboard/role-management/Form/UpdateForm/index.jsx
deleted file mode 100644
index f9defe7..0000000
--- a/src/components/dashboard/role-management/Form/UpdateForm/index.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import {Dialog, IconButton, Stack, Tooltip} from "@mui/material";
-import {useTranslations} from "next-intl";
-import {useState} from "react";
-import UpdateContent from "@/components/dashboard/role-management/Form/UpdateForm/UpdateContent";
-import EditIcon from "@mui/icons-material/Edit";
-
-const UpdateForm = ({mutate, row}) => {
- const t = useTranslations();
- const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
-
- return (
-
-
- {
- setOpenConfirmDialog(true);
- }}
- >
-
-
-
-
-
- )
-}
-export default UpdateForm
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/RoleManagementComponent.jsx b/src/components/dashboard/role-management/RoleManagementComponent.jsx
deleted file mode 100644
index 72cba70..0000000
--- a/src/components/dashboard/role-management/RoleManagementComponent.jsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import DataTable from "@/core/components/DataTable";
-import {GET_ROLES} from "@/core/data/apiRoutes";
-import TableRowActions from "@/components/dashboard/role-management/TableRowActions";
-import {Box, Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-import {useMemo} from "react";
-import moment from "jalali-moment";
-import MuiDatePicker from "@/core/components/MuiDatePicker";
-import TableToolbar from "@/components/dashboard/role-management/TableToolbar";
-
-const RoleManagementComponent = () => {
- const t = useTranslations();
-
- const columns = useMemo(() => [{
- accessorFn: (row) => row.id,
- id: "id",
- sortDescFirst: true,
- header: t("RoleManagement.id"),
- enableColumnFilter: true,
- datatype: "numeric",
- filterFn: "equals",
- columnFilterModeOptions: ["equals", "notEquals", "contains", "lessThan", "greaterThan", "between",],
- Cell: ({renderedCellValue}) => ({renderedCellValue}),
- },
- {
- accessorFn: (row) => row.name_fa,
- id: "name_fa",
- header: t("RoleManagement.name_fa"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains", "equals", "notEquals"],
- Cell: ({renderedCellValue}) => ({renderedCellValue}),
- },
- {
- accessorFn: (row) => row.name,
- id: "name",
- header: t("RoleManagement.name"),
- enableColumnFilter: true,
- datatype: "text",
- filterFn: "contains",
- columnFilterModeOptions: ["contains"],
- Cell: ({renderedCellValue}) => ({renderedCellValue}),
- },
- {
- accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
- id: "created_at",
- header: t("RoleManagement.created_at"),
- enableColumnFilter: true,
- datatype: "date",
- filterFn: "lessThan",
- columnFilterModeOptions: ["lessThan", "greaterThan"],
- Cell: ({renderedCellValue}) => {
- return {renderedCellValue};
- },
- Header: ({column}) => <>{column.columnDef.header}>,
- Filter: ({column}) => {
- return ();
- },
- }, {
- accessorFn: (row) => moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
- id: "updated_at",
- header: t("RoleManagement.updated_at"),
- enableColumnFilter: false,
- datatype: "numeric",
- Cell: ({renderedCellValue}) => ({renderedCellValue}),
- }], []);
- return (
-
-
-
- )
-}
-export default RoleManagementComponent
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/TableRowActions.jsx b/src/components/dashboard/role-management/TableRowActions.jsx
deleted file mode 100644
index d655f09..0000000
--- a/src/components/dashboard/role-management/TableRowActions.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import {Box} from "@mui/material";
-import UpdateForm from "@/components/dashboard/role-management/Form/UpdateForm";
-import DeleteForm from "@/components/dashboard/role-management/Form/DeleteForm";
-
-
-const TableRowActions = ({row, mutate}) => {
-
- return (
-
-
-
-
- );
-};
-
-export default TableRowActions;
diff --git a/src/components/dashboard/role-management/TableToolbar.jsx b/src/components/dashboard/role-management/TableToolbar.jsx
deleted file mode 100644
index 6a739a7..0000000
--- a/src/components/dashboard/role-management/TableToolbar.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import {useTranslations} from "next-intl";
-import CreateForm from "@/components/dashboard/role-management/Form/CreateForm";
-
-function TableToolbar({mutate}) {
- const t = useTranslations();
-
- return
-
-}
-
-export default TableToolbar;
diff --git a/src/components/dashboard/role-management/__test__/RoleManagementComponent.test.js b/src/components/dashboard/role-management/__test__/RoleManagementComponent.test.js
deleted file mode 100644
index a60dc01..0000000
--- a/src/components/dashboard/role-management/__test__/RoleManagementComponent.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
-import RoleManagementComponent from "@/components/dashboard/role-management/RoleManagementComponent";
-
-describe("Role Management", ()=>{
- describe("Rendering", ()=>{
- it('should see id title of data table', async () => {
- render(
-
-
-
- )
- const idEelement = screen.queryByText("کد یکتا")
- await waitFor(()=>{
- expect(idEelement).toBeInTheDocument()
- })
- });
- it('should see name title of data table', async () => {
- render(
-
-
-
- )
- const nameEelement = screen.queryByText("نام انگلیسی")
- await waitFor(()=>{
- expect(nameEelement).toBeInTheDocument()
- })
- });
- it('should see name_fa title of data table', async () => {
- render(
-
-
-
- )
- const name_faEelement = screen.queryByText("نام فارسی")
- await waitFor(()=>{
- expect(name_faEelement).toBeInTheDocument()
- })
- });
- it('should see created at title of data table', async () => {
- render(
-
-
-
- )
- const createdEelement = screen.queryByText("تاریخ درخواست")
- await waitFor(()=>{
- expect(createdEelement).toBeInTheDocument()
- })
- });
- it('should see updated at title of data table', async () => {
- render(
-
-
-
- )
- const updateEelement = screen.queryByText("تاریخ بروزرسانی")
- await waitFor(()=>{
- expect(updateEelement).toBeInTheDocument()
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/dashboard/role-management/index.jsx b/src/components/dashboard/role-management/index.jsx
deleted file mode 100644
index 6376b30..0000000
--- a/src/components/dashboard/role-management/index.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import RoleManagementComponent from "@/components/dashboard/role-management/RoleManagementComponent";
-import DashboardLayout from "@/layouts/DashboardLayout";
-import moment from "jalali-moment";
-
-function DashboardRoleManagementComponent() {
- return (
-
-
-
- );
-}
-
-export default DashboardRoleManagementComponent;
diff --git a/src/components/errors/403.jsx b/src/components/errors/403.jsx
deleted file mode 100644
index ce91443..0000000
--- a/src/components/errors/403.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import {Button, Typography} from "@mui/material";
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import {useTranslations} from "next-intl";
-import TitlePage from "@/core/components/TitlePage";
-import Svg403 from "@/core/components/svgs/Svg403";
-
-const UnAuthorizedComponent = () => {
- const t = useTranslations();
-
- return (
- <>
-
-
-
-
-
- {t("ErrorPage.custom_403")}
-
-
-
-
- >
- );
-};
-
-export default UnAuthorizedComponent;
diff --git a/src/components/errors/404.jsx b/src/components/errors/404.jsx
deleted file mode 100644
index acfd418..0000000
--- a/src/components/errors/404.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import {Button, Typography} from "@mui/material";
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import {useTranslations} from "next-intl";
-import TitlePage from "@/core/components/TitlePage";
-import Svg404 from "@/core/components/svgs/Svg404";
-
-const NotFoundComponent = () => {
- const t = useTranslations();
-
- return (
- <>
-
-
-
-
-
- {t("ErrorPage.custom_404")}
-
-
-
-
- >
- );
-};
-
-export default NotFoundComponent;
diff --git a/src/components/errors/500.jsx b/src/components/errors/500.jsx
deleted file mode 100644
index 10e9d12..0000000
--- a/src/components/errors/500.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import {Box, Button, Container, Stack, Typography} from "@mui/material";
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import {useTranslations} from "next-intl";
-import Image from "next/image";
-import TitlePage from "@/core/components/TitlePage";
-
-const ServerErrorComponent = () => {
- const t = useTranslations();
-
- return (
- <>
-
-
-
-
-
-
-
-
-
- {t("ErrorPage.custom_500")}
-
-
-
-
-
-
- >
- );
-};
-
-export default ServerErrorComponent;
diff --git a/src/components/first/__tests__/index.test.js b/src/components/first/__tests__/index.test.js
deleted file mode 100644
index 01a6d94..0000000
--- a/src/components/first/__tests__/index.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import FirstComponent from "@/components/first";
-import MockAppWithProviders from "../../../../mocks/AppWithProvider";
-import {server} from "../../../../mocks/server";
-import {rest} from "msw";
-import {GET_USER} from "@/core/data/apiRoutes";
-
-describe("First Component From First Page", () => {
- describe("Rendering", () => {
- it("App Name Text Rendered", () => {
- render();
- const appNameElement = screen.queryByText(/سامانه CRM/i);
- expect(appNameElement).toBeInTheDocument()
- });
- it("App version Text Rendered", () => {
- render();
- const versionControler = screen.queryByText(process.env.NEXT_PUBLIC_API_VERSION, {exact: false});
- expect(versionControler).toBeInTheDocument()
- });
- it("Powered By Rendered With Currect URL", () => {
- render();
- const linkElement = screen.queryByText('توسعه یافته توسط وایتل');
- expect(linkElement).toBeInTheDocument()
- expect(linkElement).toHaveAttribute('href', process.env.NEXT_PUBLIC_POWERED_BY_URL);
- });
- });
- describe("Behavioral", () => {
- it("Show Login Button And Do Not Show Dashboard Button When User Is Not Authenticated", async () => {
- render();
- await waitFor(() => {
- const authenticationButtonLogin = screen.queryByText(/ورود کارشناس/i)
- const authenticationButtonDashboard = screen.queryByText(/داشبورد/i)
- expect(authenticationButtonLogin).toBeInTheDocument()
- expect(authenticationButtonDashboard).not.toBeInTheDocument()
- })
- });
- it("Show Dashboard Button And Do Not Show Login Button When User Is Authenticated", async () => {
- localStorage.setItem("_token", 'token');
- render();
- await waitFor(() => {
- const authenticationButtonLogin = screen.queryByText(/ورود کارشناس/i)
- const authenticationButtonDashboard = screen.queryByText(/داشبورد/i)
- expect(authenticationButtonLogin).not.toBeInTheDocument()
- expect(authenticationButtonDashboard).toBeInTheDocument()
- })
- });
- it("Show Login Button And Do Not Show Dashboard Button When User Authentication Is Expired", async () => {
- localStorage.setItem("_token", 'token');
- server.use(rest.get(GET_USER, (req, res, ctx) => {
- return res(ctx.status(401))
- }))
- render();
- await waitFor(() => {
- const authenticationButtonLogin = screen.queryByText(/ورود کارشناس/i)
- const authenticationButtonDashboard = screen.queryByText(/داشبورد/i)
- expect(authenticationButtonLogin).toBeInTheDocument()
- expect(authenticationButtonDashboard).not.toBeInTheDocument()
- })
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/first/index.jsx b/src/components/first/index.jsx
deleted file mode 100644
index 1d7166d..0000000
--- a/src/components/first/index.jsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import LinkRouting, {NextLinkComposed} from "@/core/components/LinkRouting";
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import useUser from "@/lib/app/hooks/useUser";
-import {Button, Stack, Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-import SvgDashboard from "@/core/components/svgs/SvgDashboard";
-
-const FirstComponent = () => {
- const t = useTranslations();
- const {isAuth} = useUser();
-
- return (
-
-
-
-
- {t("app_name")}
-
-
-
-
-
- v{process.env.NEXT_PUBLIC_API_VERSION}
-
-
-
-
- {t("powered_by_witel")}
-
-
-
- );
-};
-
-export default FirstComponent;
diff --git a/src/components/layouts/Dashboard/Breadcrumbs/BreadcrumbItem.jsx b/src/components/layouts/Dashboard/Breadcrumbs/BreadcrumbItem.jsx
deleted file mode 100644
index c233be3..0000000
--- a/src/components/layouts/Dashboard/Breadcrumbs/BreadcrumbItem.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import LinkRouting from "@/core/components/LinkRouting";
-import {Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-
-export default function BreadcrumbItem(props) {
- const t = useTranslations();
- const isLast = props.index === props.RouterArray.length - 1;
- const url = `/${props.RouterArray.slice(0, props.index + 1).join("/")}`;
-
- return isLast ? (
-
- {t("sidebar." + props.label)}
-
- ) : (
-
- {t("sidebar." + props.label)}
-
- );
-}
diff --git a/src/components/layouts/Dashboard/Breadcrumbs/index.jsx b/src/components/layouts/Dashboard/Breadcrumbs/index.jsx
deleted file mode 100644
index 9ab234e..0000000
--- a/src/components/layouts/Dashboard/Breadcrumbs/index.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import {useRouter} from "next/router";
-import {Box, Breadcrumbs} from "@mui/material";
-import {useTheme} from "@mui/material/styles";
-import {NavigateBefore, NavigateNext} from "@mui/icons-material";
-import BreadcrumbItem from "./BreadcrumbItem";
-
-const BreadCrumbs = (props) => {
- const {isVisible} = props;
- const theme = useTheme();
- const router = useRouter();
-
- if (!isVisible) {
- return null;
- }
-
- const {pathname} = router;
- const RouterArray = pathname.split("/").filter((segment) => segment !== "");
-
- if (RouterArray.length === 1) {
- return null;
- }
-
- return (
-
-
- ) : (
-
- )
- }
- aria-label="breadcrumb"
- >
- {RouterArray.map((segment, index) => (
-
- ))}
-
-
- );
-};
-
-export default BreadCrumbs;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/__test__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/__test__/index.test.js
deleted file mode 100644
index 69f9b52..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/__test__/index.test.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import {AnswersProvider} from "@/lib/callWidget/contexts/answers";
-import ActionHeader from "..";
-
-const tab = {
- active: true,
- active_category_id: 1,
- phone_number : "09134849737"
-}
-
-describe('Action Header Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should see header text', async () => {
- render(
-
-
-
-
-
- )
- const headingElement = screen.getByRole('heading', {
- name: /\.\.\.\. عملیات های مربوط به تماس:/i
- })
- await waitFor(() => {
- expect(headingElement).toBeInTheDocument()
- })
- });
- it('should see phone number', async () => {
- render(
-
-
-
-
-
- )
- const phone_numberElement = screen.queryByText(/09134849737/i)
- await waitFor(() => {
- expect(phone_numberElement).toBeInTheDocument()
- })
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/index.jsx
deleted file mode 100644
index 97b4297..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/ActionHeader/index.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Stack, Typography} from "@mui/material";
-
-const ActionHeader = ({tab}) => {
- const t = useTranslations();
- return (
-
-
- .... {t("CallAction.call_history_of")}:
-
-
- {tab.phone_number} ....
-
-
- )
-}
-
-export default ActionHeader
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx
deleted file mode 100644
index 40c2b18..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Button, Grid } from "@mui/material";
-import useCategories from "@/lib/callWidget/hooks/useCategories";
-
-const CallActionCategoriesButton = ({ category, tab }) => {
- const { setActiveCategoryID } = useCategories();
-
- return (
-
-
-
-
-
- );
-};
-export default CallActionCategoriesButton;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/CallActionCategoriesButton.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/CallActionCategoriesButton.test.js
deleted file mode 100644
index 195df02..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/CallActionCategoriesButton.test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import {AnswersProvider} from "@/lib/callWidget/contexts/answers";
-import CallActionCategoriesButton from "../CallActionCategoriesButton";
-
-const category = {
- category_id: 1,
- category_name: "اطلاعات راه ها",
-}
-const tab = {
- active: true,
- active_category_id: 1,
-}
-
-describe('Call Action Categories Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should categories names', async () => {
- render(
-
-
-
-
-
- )
- const categoryElement = screen.queryByText("اطلاعات راه ها")
- await waitFor(() => {
- expect(categoryElement).toBeInTheDocument()
- })
- });
- });
- describe("Behavior", ()=>{
- it("Should change the color when button clecked",async()=>{
- render(
-
-
-
-
-
- )
- const buttonElement = screen.getByRole('button', {
- name: /اطلاعات راه ها/i
- })
-
- fireEvent.click(buttonElement);
-
- await waitFor(() => {
- expect(buttonElement).toHaveStyle('background-color: rgb(12, 31, 23)');
- })
- })
- })
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/index.test.js
deleted file mode 100644
index ee223ff..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/index.test.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { AnswersProvider } from "@/lib/callWidget/contexts/answers";
-import CallActionsCategories from "..";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import { render, screen, waitFor } from "@testing-library/react";
-
-const tab = {
- active: true,
- active_category_id: 1,
- id : 1,
- phone_number : "09134849737"
-}
-
-describe('Call Action Categories Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should see divider text', async () => {
- render(
-
-
-
-
-
- )
- const divider_textElement = screen.queryByText("موضوع ها")
- await waitFor(() => {
- expect(divider_textElement).toBeInTheDocument()
- })
- });
- });
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx
deleted file mode 100644
index dc814ec..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Chip, Divider, Grid, Stack } from "@mui/material";
-import useCategories from "@/lib/callWidget/hooks/useCategories";
-import CallActionCategoriesButton from "./CallActionCategoriesButton";
-import { useTranslations } from "next-intl";
-
-const CallActionsCategories = ({ tab }) => {
- const { categoryLists } = useCategories();
- const t = useTranslations();
- return (
- <>
-
-
-
- {categoryLists.map((category) => {
- return ;
- })}
-
-
- >
- );
-};
-export default CallActionsCategories;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/__test__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/__test__/index.test.js
deleted file mode 100644
index b7e0543..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/__test__/index.test.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import {fireEvent, render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import {AnswersProvider} from "@/lib/callWidget/contexts/answers";
-import CallActionDescription from "..";
-
-describe('Action Header Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should see placeholder text', async () => {
- render(
-
-
-
-
-
- )
- const textElement = screen.getByPlaceholderText('لطفا توضیحات خود را وارد نمایید')
- await waitFor(() => {
- expect(textElement).toBeInTheDocument()
- })
- });
- it('should see header text', async () => {
- render(
-
-
-
-
-
- )
- const textElement = screen.getByText('توضیحات تماس (اختیاری)')
- await waitFor(() => {
- expect(textElement).toBeInTheDocument()
- })
- });
- });
- describe("Behavior", ()=>{
- it("Should see what write in input", async()=>{
- const setDescription = jest.fn();
- render(
-
-
-
-
-
- )
- const textElement = screen.getByPlaceholderText('لطفا توضیحات خود را وارد نمایید')
-
- fireEvent.change(textElement, {target : {value : "امین"}})
-
- await waitFor(() => {
- expect(textElement).toHaveValue("امین")
- })
- })
- })
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/index.jsx
deleted file mode 100644
index 6a29324..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionDescription/index.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Box, Chip, Divider, TextField } from "@mui/material"
-import { useTranslations } from "next-intl";
-
-const CallActionDescription = ({setDescription}) => {
- const t = useTranslations();
- return(
- <>
-
-
- {
- setDescription(e.target.value)
- }}
- />
-
- >
- )
-}
-export default CallActionDescription
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx
deleted file mode 100644
index 2b4a479..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Button, Grid } from "@mui/material";
-
-const CallActionSubcategoriesButton = ({ sub_category, tab, handleSubcategoryButton }) => {
-
- return sub_category.category_id === tab.active_category_id ? (
-
-
-
- ) : null;
-};
-export default CallActionSubcategoriesButton;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/CallActionSubcategoriesButton.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/CallActionSubcategoriesButton.test.js
deleted file mode 100644
index 718f7cd..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/CallActionSubcategoriesButton.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import {AnswersProvider} from "@/lib/callWidget/contexts/answers";
-import CallActionSubcategoriesButton from "../CallActionSubcategoriesButton";
-
-const sub_category = {
- category_id: 1,
- category_name: "اطلاعات راه",
- subcategory_id: 1,
- subcategory_name: "اطلاعات باز و بسته"
-};
-
-const tab = {
- active: true,
- active_category_id: 1,
- date: new Date(),
- id: 1,
- phone_number: "09134849737"
-};
-
-describe('Call Action Subcategories Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should render subcategory name', async () => {
- render(
-
-
-
-
-
- );
- const subCategoryElement = screen.queryByText(/اطلاعات باز و بسته/i);
- await waitFor(() => {
- expect(subCategoryElement).toBeInTheDocument();
- });
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/index.test.js
deleted file mode 100644
index 2195bde..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/index.test.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { AnswersProvider } from "@/lib/callWidget/contexts/answers";
-import CallActionsSubcategories from "..";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-import { render, screen, waitFor } from "@testing-library/react";
-
-const tab = {
- active: true,
- active_category_id: 1,
- id : 1,
- phone_number : "09134849737"
-}
-
-describe('Call Action Categories Button from Call Actions Categories', () => {
- describe('Rendering', () => {
- it('should see divider text', async () => {
- render(
-
-
-
-
-
- )
- const divider_textElement = screen.queryByText("زیر موضوع ها")
- await waitFor(() => {
- expect(divider_textElement).toBeInTheDocument()
- })
- });
- });
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx
deleted file mode 100644
index 0b88cfa..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import useCategories from "@/lib/callWidget/hooks/useCategories";
-import { Chip, Divider, Grid, Stack } from "@mui/material";
-import CallActionSubcategoriesButton from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton";
-import { useTranslations } from "next-intl";
-
-const CallActionsSubcategories = ({ tab, handleSubcategoryButton }) => {
- const { subCategoryLists } = useCategories();
- const t = useTranslations();
- return (
- <>
-
-
-
- {subCategoryLists.map((sub_category, index) => {
- return ;
- })}
-
-
- >
- );
-};
-export default CallActionsSubcategories;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx
deleted file mode 100644
index 082d701..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import CallActionsCategories from "./CallActionCategories";
-import CallActionsSubcategories from "./CallActionSubcategories";
-import ActionHeader from "./ActionHeader";
-import CallActionDescription from "./CallActionDescription";
-import {CALL_ACTION} from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-import useAnswers from "@/lib/callWidget/hooks/useAnswers";
-import {useState} from "react";
-import {Stack} from "@mui/material";
-
-function CallActions({tab}) {
- const [description, setDescription] = useState('')
- const requestServer = useRequest({auth: true});
- const {closeAnswerTab} = useAnswers();
-
- const handleSubcategoryButton = (category_id, subcategory_id) => {
- requestServer(`${CALL_ACTION}/${tab.id}`, "post", {
- data: {
- category_id,
- subcategory_id,
- description
- },
- success: {
- notification: {show: false},
- },
- })
- .then(() => {
- closeAnswerTab(tab.id);
- })
- .catch(() => {
- });
- };
-
-
- return (
-
-
-
-
-
-
-
-
- );
-}
-
-export default CallActions;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/__tests__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/__tests__/index.test.js
deleted file mode 100644
index 91d5651..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/__tests__/index.test.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import ErrorOrEmpty from "../../ErrorOrEmpty";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-
-describe("ErrorOrEmpty Component From call history", () => {
- describe("Rendering", () => {
- it("error fetching history of call text rendered", () => {
- render();
- const errorText = screen.queryByText('خطا در دریافت تاریخچه تماس دریافتی');
- expect(errorText).toBeInTheDocument();
- });
- it("empty fetching history of call text rendered", () => {
- render();
- const emptyText = screen.queryByText('تاریخچه ای برای تماس دریافتی یافت نشد');
- expect(emptyText).toBeInTheDocument();
-
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/index.jsx
deleted file mode 100644
index bb0f818..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Typography} from "@mui/material";
-
-const ErrorOrEmpty = ({isErrorOrEmpty}) => {
- const t = useTranslations();
- return (
- <>
- {isErrorOrEmpty === "error" ?
-
- {t("CallHistory.call_history_error_fetching")}
-
- : isErrorOrEmpty === "empty" ?
-
- {t("CallHistory.call_history_not_found")}
- : <>>
- }
- >
- )
-}
-
-export default ErrorOrEmpty
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/__tests__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/__tests__/index.test.js
deleted file mode 100644
index 51d700e..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/__tests__/index.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import HistoryHeader from "../../HistoryHeader";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-
-describe("HistoryHeader Component From call history", () => {
- describe("Rendering", () => {
- const tab = {
- phone_number: "09111111111"
- }
- it("text of header rendered", () => {
- render();
- const textHeader = screen.queryByText(/تاریخچه تماس های/i);
- expect(textHeader).toBeInTheDocument();
- });
- it("caller number in header rendered", () => {
- render();
- const callerNumber = screen.queryByText(/09111111111/i);
- expect(callerNumber).toBeInTheDocument();
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/index.jsx
deleted file mode 100644
index 21a3270..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/HistoryHeader/index.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Stack, Typography} from "@mui/material";
-
-const HistoryHeader = ({tab}) => {
- const t = useTranslations();
- return (
-
-
- .... {t("CallHistory.call_history_of")}:
-
-
- {tab.phone_number} ....
-
-
- )
-}
-
-export default HistoryHeader
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/__tests__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/__tests__/index.test.js
deleted file mode 100644
index 4fd4519..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/__tests__/index.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../../mocks/AppWithProvider";
-import PreviousOperatorData from "../../PreviousOperatorData";
-
-describe("PreviousOperatorData Component From call history", () => {
- describe("Rendering", () => {
- const historyItem = {
- operator_name: "test name",
- answer_date: "test date"
- }
- it("operator name rendered", () => {
- render();
- const operatorName = screen.queryByText("test name");
- expect(operatorName).toBeInTheDocument();
- });
- it("operator answer date rendered", () => {
- render();
- const operatorAnswerDate = screen.queryByText("test date");
- expect(operatorAnswerDate).toBeInTheDocument();
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/index.jsx
deleted file mode 100644
index afd2ad7..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData/index.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Avatar, Box, ListItem, ListItemAvatar, ListItemText, Typography} from "@mui/material";
-import HeadsetMicIcon from '@mui/icons-material/HeadsetMic';
-
-const PreviousOperatorData = ({historyItem}) => {
- const t = useTranslations();
- return (
-
-
-
-
-
-
-
-
- {historyItem.operator_name}
-
-
- ({t("CallHistory.operator")})
-
-
- } secondary={historyItem.answer_date}/>
-
- )
-}
-
-export default PreviousOperatorData
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/__tests__/index.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/__tests__/index.test.js
deleted file mode 100644
index d9d77e4..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/__tests__/index.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../../../../mocks/AppWithProvider";
-import Topics from "../../Topics";
-
-describe("Topics Component From call history", () => {
- describe("Rendering", () => {
- const historyItem = {
- category_name: "test category",
- subcategory_name: "test sub category"
- }
- it("operator name rendered", () => {
- render();
- const operatorName = screen.queryByText("test category");
- expect(operatorName).toBeInTheDocument();
- });
- it("operator answer date rendered", () => {
- render();
- const operatorAnswerDate = screen.queryByText("test sub category");
- expect(operatorAnswerDate).toBeInTheDocument();
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/index.jsx
deleted file mode 100644
index 3b57744..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics/index.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Box, List, ListItem, Typography} from "@mui/material";
-
-const Topics = ({historyItem}) => {
- const t = useTranslations();
- return (
-
-
-
-
-
- {t("CallHistory.category_name")}:
-
-
- {historyItem.category_name}
-
-
-
-
-
-
-
-
- {t("CallHistory.subcategory_name")}:
-
-
- {historyItem.subcategory_name}
-
-
-
-
-
- )
-}
-
-export default Topics
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx
deleted file mode 100644
index 7af4fd5..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Grow, List} from "@mui/material";
-import PreviousOperatorData from "./PreviousOperatorData";
-import Topics from "./Topics";
-
-const ListItemOfCalls = ({historyItem}) => {
- const t = useTranslations();
-
- // console.log(historyItem)
-
- return (
-
-
-
-
-
-
- )
-}
-
-export default ListItemOfCalls
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/__tests__/intex.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/__tests__/intex.test.js
deleted file mode 100644
index 1592a02..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/__tests__/intex.test.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import LoadingHistory from "../../LoadingHistory";
-import MockAppWithProviders from "../../../../../../../../../../../mocks/AppWithProvider";
-
-describe("LoadingHistory Component From call history", () => {
- describe("Rendering", () => {
- it("loading list rendered", () => {
- render();
- const loadingList = screen.queryByTestId("loading-list");
- expect(loadingList).toBeInTheDocument();
- });
- it("loading list item avatar rendered", () => {
- render();
- const loadingListItemAvatar = screen.queryByTestId("loading-listItemAvatar");
- expect(loadingListItemAvatar).toBeInTheDocument();
- });
- it("loading list item text rendered", () => {
- render();
- const loadingListItemText = screen.queryByTestId("loading-listItemText");
- expect(loadingListItemText).toBeInTheDocument();
- });
- it("loading list item category rendered", () => {
- render();
- const loadingListItemCat = screen.queryByTestId("loading-listItem-cat");
- expect(loadingListItemCat).toBeInTheDocument();
- });
- it("loading list item sub category rendered", () => {
- render();
- const loadingListItemSubCat = screen.queryByTestId("loading-listItem-subCat");
- expect(loadingListItemSubCat).toBeInTheDocument();
- });
- it("operator avatar skeleton rendered", () => {
- render();
- const operatorAvatarSkeleton = screen.queryByTestId("operator-avatar-skeleton");
- expect(operatorAvatarSkeleton).toBeInTheDocument();
- });
- it("operator name skeleton rendered", () => {
- render();
- const operatorNameSkeleton = screen.queryByTestId("operator-name-skeleton");
- expect(operatorNameSkeleton).toBeInTheDocument();
- });
- it("operator answer date skeleton rendered", () => {
- render();
- const operatorAnswerDateSkeleton = screen.queryByTestId("operator-answer-date-skeleton");
- expect(operatorAnswerDateSkeleton).toBeInTheDocument();
- });
- it("operator category header skeleton rendered", () => {
- render();
- const operatorCategoryHeaderSkeleton = screen.queryByTestId("operator-category-header-skeleton");
- expect(operatorCategoryHeaderSkeleton).toBeInTheDocument();
- });
- it("operator category value skeleton rendered", () => {
- render();
- const operatorCategoryValueSkeleton = screen.queryByTestId("operator-category-value-skeleton");
- expect(operatorCategoryValueSkeleton).toBeInTheDocument();
- });
- it("operator subCategory header skeleton rendered", () => {
- render();
- const operatorSubCategoryHeaderSkeleton = screen.queryByTestId("operator-subCategory-header-skeleton");
- expect(operatorSubCategoryHeaderSkeleton).toBeInTheDocument();
- });
- it("operator subCategory value skeleton rendered", () => {
- render();
- const operatorSubCategoryValueSkeleton = screen.queryByTestId("operator-subCategory-value-skeleton");
- expect(operatorSubCategoryValueSkeleton).toBeInTheDocument();
- });
- });
-});
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/index.jsx
deleted file mode 100644
index 2c9900e..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/LoadingHistory/index.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Box, List, ListItem, ListItemAvatar, ListItemText, Skeleton} from "@mui/material";
-
-const LoadingHistory = () => {
- const t = useTranslations();
- return (
- <>
-
-
-
-
-
-
-
-
- } secondary={
-
- }/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
-
- )
-}
-
-export default LoadingHistory
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx
deleted file mode 100644
index 9d61cce..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import {useTranslations} from "next-intl";
-import {Box, Chip, Divider, Stack} from "@mui/material";
-import HeadphonesIcon from '@mui/icons-material/Headphones';
-import LoadingHistory from "./LoadingHistory";
-import HistoryHeader from "./HistoryHeader";
-import ErrorOrEmpty from "./ErrorOrEmpty";
-import useCallerHistory from "@/lib/callWidget/hooks/useCallerHistory";
-import ListItemOfCalls from "./ListItemOfCalls";
-import {useState} from "react";
-
-const max_size = 10;
-const CallHistory = ({tab}) => {
- const t = useTranslations();
- const {
- firstItemOfHistory,
- historyList,
- isLoadingHistoryList,
- errorHistoryList
- } = useCallerHistory(tab.id, tab.phone_number, max_size);
- const [showRestOfHistory, setShowRestOfHistory] = useState(false);
-
- return (
-
-
-
- {isLoadingHistoryList ? (
-
- ) : errorHistoryList ? (
-
- ) : !firstItemOfHistory ? (
-
- ) : (
-
-
- {historyList && (
-
- }
- onClick={() => setShowRestOfHistory(true)}
- label={t("show_more")}
- disabled={showRestOfHistory}
- />
-
- )}
- {showRestOfHistory && (
- <>
- {historyList.map((historyItem, index) => (
- <>
-
-
- >
- ))}
- >)
- }
-
- )}
-
-
- )
-}
-
-export default CallHistory
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx
deleted file mode 100644
index be7e9d2..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import {Divider, Grid} from "@mui/material";
-import CallActions from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions";
-import CallHistory from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory";
-
-const CallTabPanel = ({tab}) => {
- return (
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default CallTabPanel
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabDetails.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabDetails.jsx
deleted file mode 100644
index 9427201..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabDetails.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import {Stack, Typography} from "@mui/material";
-import CallIcon from '@mui/icons-material/Call';
-import CallTabTime from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabTime";
-
-const CallTabDetails = ({tab}) => {
-
- return (
-
-
-
- {tab.phone_number}
-
-
-
- )
-}
-export default CallTabDetails
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx
deleted file mode 100644
index e49bcdc..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import {IconButton, Stack, Zoom} from "@mui/material";
-import CloseIcon from '@mui/icons-material/Close';
-import useAnswers from "@/lib/callWidget/hooks/useAnswers";
-import CallTabDetails
- from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabDetails";
-
-const CallTabLabel = ({tab, index}) => {
- const {closeAnswerTab, activeTab} = useAnswers()
- const handleCloseClick = (id) => {
- closeAnswerTab(id)
- };
-
- return (
-
-
-
- handleCloseClick(tab.id)}>
-
-
-
-
- )
-}
-
-export default CallTabLabel
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabTime.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabTime.jsx
deleted file mode 100644
index 5d627e4..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabTime.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import {Typography} from "@mui/material";
-import {useEffect, useState} from "react";
-import moment from "jalali-moment";
-import useLanguage from "@/lib/app/hooks/useLanguage";
-
-const CallTabTime = ({realTimeDate}) => {
- const {languageApp} = useLanguage()
- const [date, setDate] = useState('...')
- const changeTabTime = (tabTime) => {
- moment.relativeTimeThreshold('ss', 1)
- return moment(tabTime).locale(languageApp).fromNow()
- }
-
- useEffect(() => {
- const timer = setInterval(() => {
- setDate(changeTabTime(realTimeDate))
- }, 1000)
-
- return () => {
- clearInterval(timer)
- }
- }, [realTimeDate]);
-
- return (
- {date}
- )
-}
-export default CallTabTime
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabDetails.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabDetails.test.js
deleted file mode 100644
index 7d50bff..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabDetails.test.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
-import CallTabDetails
- from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabDetails";
-
-
-const tab = {
- phone_number: "09134849737",
- id: 1,
- date: new Date()
-}
-
-describe("Call Tab Details from Call Tan List", () => {
- describe("Rendering", () => {
- it('Should see the phone number on tab detail', async () => {
- render(
-
-
-
- )
- const phoneNumberElement = screen.getByText("09134849737")
- await waitFor(() => {
- expect(phoneNumberElement).toHaveTextContent("09134849737")
- })
- });
-
- })
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabTime.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabTime.test.js
deleted file mode 100644
index 31b9a1b..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/__test__/CallTabTime.test.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../../../../mocks/AppWithProvider";
-import CallTabTime from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabTime";
-
-const tab = {
- phone_number: "09134849737",
- id: 1,
- date: new Date()
-}
-
-describe("Call Tab Details from Call Tan List", () => {
- describe("Rendering", () => {
- it('Should see the date on tab detail', async () => {
- render(
-
-
-
- )
-
- await waitFor(() => {
- expect(screen.getByText(/ثانیه پیش/i)).toBeInTheDocument()
- })
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx
deleted file mode 100644
index ff26544..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {Box, Tab, Tabs} from "@mui/material";
-import CallTabLabel
- from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel";
-import useAnswers from "@/lib/callWidget/hooks/useAnswers";
-
-const CallTabsList = () => {
- const {answersList, changeActiveTabAnswers, activeTab} = useAnswers()
- const handleChange = (event, newValue) => {
- changeActiveTabAnswers(newValue)
- };
-
- return (
-
-
- {answersList.map((answer, index) => (
- } key = {answer.id}/>
- ))}
-
-
- )
-}
-
-export default CallTabsList
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx
deleted file mode 100644
index 8a96506..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import CallTabPanel from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel";
-import useAnswers from "@/lib/callWidget/hooks/useAnswers";
-import CallTabsList from "src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList";
-
-const CallTabs = () => {
- const {answersList} = useAnswers()
-
- return (
- <>
-
- {answersList.map((answer) => (
-
- ))}
- >
- )
-}
-export default CallTabs
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx
deleted file mode 100644
index e7d4278..0000000
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import {Dialog} from "@mui/material";
-import {DialogTransition} from "@/core/components/DialogTransition";
-import {useEffect} from "react";
-import useCallDialog from "@/lib/callWidget/hooks/useCallDialog";
-import useAnswers from "@/lib/callWidget/hooks/useAnswers";
-import useSocket from "@/lib/app/hooks/useSocket";
-import CallTabs from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs";
-
-const CallWidgetDialog = () => {
- const {openCallDialog, setOpenCallDialog} = useCallDialog()
- const {answersList, newAnswerTab} = useAnswers()
- const socket = useSocket()
-
- useEffect(() => {
- const answerCall = (_data, act) => {
- const data = JSON.parse(_data)
- newAnswerTab({
- id: data.call_id,
- phone_number: data.phone_number
- })
- act()
- }
- socket.on('answer', answerCall)
-
- return () => {
- socket.off('answer', answerCall)
- }
- });
-
- useEffect(() => {
- if (answersList.length === 0) {
- setOpenCallDialog(false)
- return
- }
- setOpenCallDialog(true)
- }, [answersList.length]);
-
- return (
-
- )
-}
-
-export default CallWidgetDialog
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/CallWidget/index.jsx b/src/components/layouts/Dashboard/CallWidget/index.jsx
deleted file mode 100644
index 1480498..0000000
--- a/src/components/layouts/Dashboard/CallWidget/index.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import CallWidgetDialog from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog";
-import {AnswersProvider} from "@/lib/callWidget/contexts/answers";
-import useSocket from "@/lib/app/hooks/useSocket";
-import {useEffect} from "react";
-
-const CallWidget = () => {
- const socket = useSocket()
-
- useEffect(() => {
- if (socket.connected) return
-
- socket.connect()
-
- return () => {
- socket.disconnect()
- }
- }, []);
-
- return (
-
-
-
- )
-}
-
-export default CallWidget
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/Header/ProfileData.jsx b/src/components/layouts/Dashboard/Header/ProfileData.jsx
deleted file mode 100644
index 548378b..0000000
--- a/src/components/layouts/Dashboard/Header/ProfileData.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import {Avatar, Stack, Typography} from "@mui/material";
-import useUser from "@/lib/app/hooks/useUser";
-
-export default function ProfileData() {
- const {user} = useUser();
- return (
-
-
-
- {user.username}
-
-
- );
-}
diff --git a/src/components/layouts/Dashboard/Header/ProfileMenu.jsx b/src/components/layouts/Dashboard/Header/ProfileMenu.jsx
deleted file mode 100644
index 415d501..0000000
--- a/src/components/layouts/Dashboard/Header/ProfileMenu.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import {Avatar, IconButton, Menu, Tooltip} from "@mui/material";
-import {useState} from "react";
-import ProfileData from "./ProfileData";
-import ProfileOptions from "./ProfileOptions";
-import {useTranslations} from "next-intl";
-import useUser from "@/lib/app/hooks/useUser";
-
-function ProfileMenu() {
- const t = useTranslations();
- const [anchorElUser, setAnchorElUser] = useState(null);
- const {user} = useUser();
-
- const handleOpenUserMenu = (event) => {
- setAnchorElUser(event.currentTarget);
- };
- const handleCloseUserMenu = () => {
- setAnchorElUser(null);
- };
-
- return (
- <>
-
-
-
-
-
-
- >
- );
-}
-
-export default ProfileMenu;
diff --git a/src/components/layouts/Dashboard/Header/ProfileOptionLogOut.jsx b/src/components/layouts/Dashboard/Header/ProfileOptionLogOut.jsx
deleted file mode 100644
index 2a6cf85..0000000
--- a/src/components/layouts/Dashboard/Header/ProfileOptionLogOut.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import {Box, Button, MenuItem, Typography} from "@mui/material";
-import MeetingRoomIcon from "@mui/icons-material/MeetingRoom";
-import useUser from "@/lib/app/hooks/useUser";
-import {useTranslations} from "next-intl";
-
-export default function ProfileOptionLogOut({handleCloseUserMenu}) {
- const t = useTranslations();
- const {clearToken} = useUser();
- const handleClickLogOut = () => {
- handleCloseUserMenu();
- clearToken();
- };
- return (
- <>
-
- >
- );
-}
diff --git a/src/components/layouts/Dashboard/Header/ProfileOptions.jsx b/src/components/layouts/Dashboard/Header/ProfileOptions.jsx
deleted file mode 100644
index 6e7bdba..0000000
--- a/src/components/layouts/Dashboard/Header/ProfileOptions.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import {Box, MenuItem, Typography} from "@mui/material";
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import {useTranslations} from "next-intl";
-import headerProfileItems from "@/core/data/headerProfileItems";
-import ProfileOptionLogOut from "./ProfileOptionLogOut";
-
-export default function ProfileOptions({handleCloseUserMenu}) {
- const t = useTranslations();
-
- return (
- <>
- {headerProfileItems.map((profile_item) => (
-
- ))}
-
- >
- );
-}
diff --git a/src/components/layouts/Dashboard/Header/index.jsx b/src/components/layouts/Dashboard/Header/index.jsx
deleted file mode 100644
index e8af065..0000000
--- a/src/components/layouts/Dashboard/Header/index.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import MenuIcon from "@mui/icons-material/Menu";
-import ProfileMenu from "./ProfileMenu";
-import {useTheme} from "@mui/material/styles";
-import CssBaseline from "@mui/material/CssBaseline";
-import {AppBar, Box, Container, IconButton, Stack, Toolbar} from "@mui/material";
-
-function Header({drawerWidth, handleDrawerToggle}) {
- const theme = useTheme();
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
-export default Header;
diff --git a/src/components/layouts/Dashboard/Sidebar/SidebarDrawer.jsx b/src/components/layouts/Dashboard/Sidebar/SidebarDrawer.jsx
deleted file mode 100644
index 3f1d449..0000000
--- a/src/components/layouts/Dashboard/Sidebar/SidebarDrawer.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import {Divider, Stack, Toolbar, Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-import SidebarList from "./SidebarList";
-import useUser from "@/lib/app/hooks/useUser";
-
-const SidebarDrawer = ({handleDrawerToggle}) => {
- const {user} = useUser();
- const t = useTranslations();
- return (
- <>
-
-
-
- {t("app_short_name")}
-
-
- {user.full_name} | {user.position}
-
-
-
-
-
- >
- );
-};
-
-export default SidebarDrawer;
diff --git a/src/components/layouts/Dashboard/Sidebar/SidebarList.jsx b/src/components/layouts/Dashboard/Sidebar/SidebarList.jsx
deleted file mode 100644
index 1e570f5..0000000
--- a/src/components/layouts/Dashboard/Sidebar/SidebarList.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import {Divider, List} from "@mui/material";
-import {Fragment, useEffect, useReducer} from "react";
-import SidebarListItem from "./SidebarListItem";
-import sidebarMenu from "@/core/data/sidebarMenu";
-import {useRouter} from "next/router";
-import useUser from "@/lib/app/hooks/useUser";
-
-function reducer(state, action) {
- switch (action.type) {
- case "COLLAPSE_MENU":
- return state.map((itemsArr) =>
- itemsArr.map((item) =>
- action.key === item.key ? { ...item, showSubItem: !item.showSubItem } : item
- )
- );
- case "SELECTED":
- return state.map((itemsArr) =>
- itemsArr.map((item) => ({
- ...item,
- selected: item.type === "page" && action.route === item.route,
- }))
- );
- default:
- throw new Error();
- }
-}
-
-export default function SidebarList({handleDrawerToggle}) {
- const [itemMenu, dispatch] = useReducer(reducer, sidebarMenu);
- const {user} = useUser();
- const router = useRouter();
-
- useEffect(() => {
- dispatch({type: "SELECTED", route: router.pathname});
- }, [router.pathname]);
-
- return (
-
- {itemMenu.map((itemArr, index) => (
-
- {itemArr.map((item) =>
-
- {(user?.permissions?.includes(item.permission) || item.permission === "all") &&
- }
-
- )}
-
-
- ))}
-
-
- );
-}
diff --git a/src/components/layouts/Dashboard/Sidebar/SidebarListItem.jsx b/src/components/layouts/Dashboard/Sidebar/SidebarListItem.jsx
deleted file mode 100644
index 2195ed3..0000000
--- a/src/components/layouts/Dashboard/Sidebar/SidebarListItem.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import ExpandLess from "@mui/icons-material/ExpandLess";
-import ExpandMore from "@mui/icons-material/ExpandMore";
-import {Badge, IconButton, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography,} from "@mui/material";
-import {useTranslations} from "next-intl";
-import {Fragment} from "react";
-import SidebarListSubItem from "./SidebarListSubItem";
-import useNotification from "@/lib/app/hooks/useNotification";
-
-const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
- const t = useTranslations();
- const { notification_count } = useNotification();
-
- const hasSubItems = item.type === "menu" && item.subItem && item.subItem.length > 0;
-
- const renderBadge = () => (
-
-
-
- );
-
- return (
- <>
-
- {
- if (hasSubItems) {
- dispatch({ type: "COLLAPSE_MENU", key: item.key });
- }
- }}
- sx={{
- minHeight: 48,
- }}
-
- >
-
- {item.icon}
-
-
- {t(item.secondary)}
-
- ) : null
- }
- />
-
- {hasSubItems && (item.showSubItem ? : )}
-
-
- {item.subItem && (
-
- )}
- >
- );
-};
-
-export default SidebarListItem;
diff --git a/src/components/layouts/Dashboard/Sidebar/SidebarListSubItem.jsx b/src/components/layouts/Dashboard/Sidebar/SidebarListSubItem.jsx
deleted file mode 100644
index 1803b96..0000000
--- a/src/components/layouts/Dashboard/Sidebar/SidebarListSubItem.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import {NextLinkComposed} from "@/core/components/LinkRouting";
-import {
- Badge,
- Collapse,
- IconButton,
- List,
- ListItem,
- ListItemButton,
- ListItemIcon,
- ListItemText,
- Typography,
-} from "@mui/material";
-import {useTranslations} from "next-intl";
-import useNotification from "@/lib/app/hooks/useNotification";
-
-const SidebarListSubItem = ({item, handleDrawerToggle}) => {
- const t = useTranslations();
- const {notification_count} = useNotification();
-
- const renderBadge = (subitem) => (
-
-
-
- );
-
- return (
-
-
- {item.subItem.map((subitem) => (
-
-
-
- {subitem.icon}
-
-
- {t(subitem.secondary)}
-
- ) : null
- }/>
-
-
- ))}
-
-
- );
-};
-
-export default SidebarListSubItem;
diff --git a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarDrawer.test.js b/src/components/layouts/Dashboard/Sidebar/__test__/SidebarDrawer.test.js
deleted file mode 100644
index e095ffc..0000000
--- a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarDrawer.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
-import SidebarDrawer from "@/components/layouts/Dashboard/Sidebar/SidebarDrawer";
-
-describe('SidebarDrawer', () => {
- describe('Rendering', () => {
- it('renders system name in sidebar', async () => {
- render();
- await waitFor(()=>{
- const systemName = screen.getByRole('heading', { level: 6 });
- expect(systemName).toHaveTextContent('سامانه CRM');
- })
- });
- it('renders user full name and position in sidebar', async () => {
- localStorage.setItem("_token", 'token');
- render();
- await waitFor(()=>{
- const userName = screen.queryByText(/Witel Company | Software Engineer/i);
- expect(userName).toBeInTheDocument();
- })
- });
- })
-})
diff --git a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarList.test.js b/src/components/layouts/Dashboard/Sidebar/__test__/SidebarList.test.js
deleted file mode 100644
index 1897c9b..0000000
--- a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarList.test.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {render, screen, waitFor} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
-import SidebarList from "@/components/layouts/Dashboard/Sidebar/SidebarList";
-
-describe('SidebarList', () => {
- describe('Rendering', () => {
- it('renders sidebar items based on user permissions', async () => {
- localStorage.setItem("_token", 'token');
- render();
- await waitFor(()=>{
- const sidebarItem = screen.getByText('مدیریت نقش ها');
- expect(sidebarItem).toBeInTheDocument();
- })
- });
- })
-})
diff --git a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListItem.test.js b/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListItem.test.js
deleted file mode 100644
index 18313c5..0000000
--- a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListItem.test.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import AccessibilityIcon from "@mui/icons-material/Accessibility";
-import {fireEvent, render, screen} from "@testing-library/react";
-import SidebarListItem from "@/components/layouts/Dashboard/Sidebar/SidebarListItem";
-import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
-
-describe('SidebarListItemComponent', () => {
- describe('Rendering', () => {
- it('should show sidebarlistitem name in sidebar', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "page",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- }
- render();
- expect(screen.getByText('مدیریت نقش ها')).toBeInTheDocument();
- });
- it('should show sidebarlistitem icon in sidebar', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "page",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- }
- render();
- const iconElement = screen.getByLabelText("Sidebar Icon");
- expect(iconElement).toBeInTheDocument();
- });
- it('should have selected class for subitem', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "page",
- route: "/dashboard/role-management",
- icon: ,
- selected: true,
- permission: "manage_roles",
- }
- render();
- const element = screen.getByText('مدیریت نقش ها');
- expect(element.parentElement.parentElement).toHaveClass('Mui-selected');
- });
-
- it('should not have selected class for subitem', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- }
- render();
- const element = screen.getByText('مدیریت نقش ها');
- expect(element.parentElement.parentElement).not.toHaveClass('Mui-selected');
- });
-
- it('should show sidebarlistitem secondary in sidebar', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- secondary: "between",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- }
- render();
- expect(screen.getByText('میان')).toBeInTheDocument();
- });
-
- it('should not show sidebarlistitem secondary in sidebar', () => {
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- }
- render();
- expect(screen.queryByText('secondry')).not.toBeInTheDocument();
- });
- })
- describe('Behavior', () => {
- it('should call dispatch when hasSubItems is true and item is clicked', () => {
- const dispatchMock = jest.fn();
- const sampleItem={
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- subItem :[
- {
- key: "greaterThan",
- route: "/dashboard/role-management",
- secondary: "between",
- name : "sidebar.admin",
- selected: true,
- icon: ,
- }
- ]
- }
- render();
- const listItem = screen.getByText('مدیریت نقش ها');
- fireEvent.click(listItem);
- expect(dispatchMock).toHaveBeenCalledWith({
- type: 'COLLAPSE_MENU',
- key: "sidebar.role-management",
- });
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListSubitem.test.js b/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListSubitem.test.js
deleted file mode 100644
index 9551937..0000000
--- a/src/components/layouts/Dashboard/Sidebar/__test__/SidebarListSubitem.test.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
-import SidebarListSubItem from "@/components/layouts/Dashboard/Sidebar/SidebarListSubItem";
-import AccessibilityIcon from "@mui/icons-material/Accessibility";
-
-describe('SidebarListSubItemComponent', () => {
- describe('Rendering', () => {
- const sampleItem={
- showSubItem:true,
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- subItem :[
- {
- key: "greaterThan",
- route: "/dashboard/role-management",
- secondary: "between",
- name : "sidebar.admin",
- selected: true,
- icon: ,
- }
- ]
- }
- it('should show subitem name in sidebar', () => {
- render();
- expect(screen.getByText('بزرگتر از')).toBeInTheDocument();
-
- });
- it('should not show subitem name in sidebar', () => {
- const sampleItem={
- showSubItem:false,
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- subItem :[
- {
- key: "greaterThan",
- route: "/dashboard/role-management",
- secondary: "between",
- name : "sidebar.admin",
- selected: false,
- icon: ,
- }
- ]
- }
- render();
- expect(screen.queryByText('مدیریت نقش ها')).not.toBeInTheDocument();
- });
- it('should show subitem secondary in sidebar', () => {
- render();
- expect(screen.getByText('میان')).toBeInTheDocument();
- });
-
- it('should not show subitem secondary in sidebar', () => {
- render();
- expect(screen.queryByText('secondry')).not.toBeInTheDocument();
- });
- it('should have selected class for subitem', () => {
- render();
- const parentElement = screen.queryByText('بزرگتر از').parentElement.parentElement;
- expect(parentElement).toHaveClass('Mui-selected');
- });
-
- it('should not have selected class for subitem', () => {
- const sampleItem={
- showSubItem:true,
- key: "sidebar.role-management",
- name : "role_management",
- type: "menu",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- subItem :[
- {
- key: "greaterThan",
- route: "/dashboard/role-management",
- secondary: "between",
- name : "sidebar.admin",
- selected: false,
- icon: ,
- }
- ]
- }
- render();
- const parentElement = screen.queryByText('بزرگتر از').parentElement.parentElement;
- expect(parentElement).not.toHaveClass('Mui-selected');
- });
- it('should show subitem icon', () => {
- render();
- const iconElement = screen.getByLabelText("Sidebar Icon");
- expect(iconElement).toBeInTheDocument();
- });
- })
-})
\ No newline at end of file
diff --git a/src/components/layouts/Dashboard/Sidebar/__test__/index.test.js b/src/components/layouts/Dashboard/Sidebar/__test__/index.test.js
deleted file mode 100644
index 740c384..0000000
--- a/src/components/layouts/Dashboard/Sidebar/__test__/index.test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import {render, screen, act} from "@testing-library/react";
-import MockAppWithProviders from "../../../../../../mocks/AppWithProvider";
-import Sidebar from "@/components/layouts/Dashboard/Sidebar";
-
-
-describe('Sidebar', () => {
- describe('Rendering', () => {
- it('Mobile Drawer is displayed when mobileOpen is true', () => {
- const props={
- mobileOpen: true,
- };
- render();
- const mobileDrawer = screen.getByTestId('mobile-drawer');
- expect(mobileDrawer).toBeVisible();
- });
- })
-})
diff --git a/src/components/layouts/Dashboard/Sidebar/index.jsx b/src/components/layouts/Dashboard/Sidebar/index.jsx
deleted file mode 100644
index c0b6d6d..0000000
--- a/src/components/layouts/Dashboard/Sidebar/index.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import {Box, Drawer} from "@mui/material";
-import SidebarDrawer from "./SidebarDrawer";
-
-const Sidebar = (props) => {
- return (
-
-
-
-
-
-
-
-
- );
-};
-
-export default Sidebar;
diff --git a/src/components/layouts/Dashboard/index.jsx b/src/components/layouts/Dashboard/index.jsx
deleted file mode 100644
index 3ee24c6..0000000
--- a/src/components/layouts/Dashboard/index.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import Header from "src/components/layouts/Dashboard/Header";
-import Sidebar from "src/components/layouts/Dashboard/Sidebar";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import {Toolbar} from "@mui/material";
-import BreadCrumbs from "src/components/layouts/Dashboard/Breadcrumbs";
-import {useState} from "react";
-
-const drawerWidth = 240;
-
-const Dashboard = (props) => {
- const {window} = props;
- const [mobileOpen, setMobileOpen] = useState(false);
- const container =
- window !== undefined ? () => window().document.body : undefined;
-
- const handleDrawerToggle = () => {
- setMobileOpen(!mobileOpen);
- };
- return (
-
-
-
-
-
-
-
- {props.children}
-
-
-
- )
-}
-
-export default Dashboard
\ No newline at end of file
diff --git a/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx
new file mode 100644
index 0000000..74c471a
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx
@@ -0,0 +1,60 @@
+import { ExpandLess, ExpandMore, Link } from "@mui/icons-material";
+import {
+ Button,
+ Divider,
+ ListItemIcon,
+ ListItemText,
+ Menu,
+ MenuItem,
+ Stack,
+} from "@mui/material";
+import NextLink from "next/link";
+import { useState } from "react";
+
+const HeaderMenu = ({ menu }) => {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+
+ const handleClick = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+ : }
+ >
+ {menu.title}
+
+
+
+ );
+};
+
+export default HeaderMenu;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx
new file mode 100644
index 0000000..239a5e6
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx
@@ -0,0 +1,19 @@
+import { getValueByPath } from "@/core/utils/getValueByPath";
+import { useSidebarBadge } from "@/lib/hooks/useSidebarBadge";
+import { Chip } from "@mui/material";
+import { useEffect, useState } from "react";
+
+const SidebarBadge = ({ badge, chipProps = {} }) => {
+ const { data } = useSidebarBadge();
+ const [value, setValue] = useState();
+
+ useEffect(() => {
+ setValue(getValueByPath(data, badge));
+ }, [data, badge]);
+
+ if (!data) return null;
+ if (!value) return null;
+
+ return ;
+};
+export default SidebarBadge;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx
new file mode 100644
index 0000000..4b4e640
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx
@@ -0,0 +1,92 @@
+import { ExpandLess, ExpandMore } from "@mui/icons-material";
+import {
+ Collapse,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+ Stack,
+} from "@mui/material";
+import Link from "next/link";
+import SidebarBadge from "./SidebarBadge";
+import SidebarSubitems from "./SidebarSubitems";
+
+const SidebarListItems = ({ menuItem, dispatch }) => {
+ return (
+ <>
+
+ {
+ if (menuItem.type !== "page") {
+ dispatch({ type: "COLLAPSE_MENU", id: menuItem.id });
+ }
+ }}
+ >
+
+ {menuItem.icon}
+
+
+ {menuItem.badges && (
+
+ {menuItem.badges.map((badge, i) => (
+
+ ))}
+
+ )}
+ {menuItem.hasSubitems ? (
+ menuItem.showSubitems ? (
+
+ ) : (
+
+ )
+ ) : null}
+
+
+
+ {menuItem.hasSubitems ? (
+
+ {menuItem.Subitems.map((subitem, index) => {
+ return (
+
+ );
+ })}
+
+ ) : null}
+
+ >
+ );
+};
+export default SidebarListItems;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx
new file mode 100644
index 0000000..29c2b09
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx
@@ -0,0 +1,128 @@
+"use client";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+import { List } from "@mui/material";
+import { usePathname } from "next/navigation";
+import { useEffect, useReducer, useState } from "react";
+import { filterMenuItems } from "@/core/utils/filterMenuItems";
+import { pageMenu } from "@/core/utils/pageMenu";
+import SidebarListItems from "./SidebarListItems";
+import Profile from "@/core/components/Profile";
+
+function selectPage(item, route) {
+ if (item.type === "page") {
+ return {
+ ...item,
+ selected: item.route === route,
+ showSubitems: item.route === route,
+ };
+ } else if (item.Subitems && Array.isArray(item.Subitems)) {
+ const updatedSubitems = item.Subitems.map((subitem) =>
+ selectPage(subitem, route),
+ );
+ return {
+ ...item,
+ Subitems: updatedSubitems,
+ showSubitems: updatedSubitems.some(
+ (subitem) => subitem.showSubitems || subitem.route === route,
+ ),
+ };
+ }
+ return item;
+}
+
+function toggleSubitems(items, actionId) {
+ return items.map((item) =>
+ actionId === item.id
+ ? { ...item, showSubitems: !item.showSubitems }
+ : { ...item, showSubitems: false },
+ );
+}
+
+function reducer(state, action) {
+ switch (action.type) {
+ case "UPDATE_MENU":
+ const _permissions = action.permissions || [];
+ return filterMenuItems(state, ["all", ..._permissions]);
+
+ case "COLLAPSE_MENU":
+ return state.map((item) => ({
+ ...item,
+ showSubitems: item.id === action.id ? !item.showSubitems : false,
+ }));
+
+ case "COLLAPSE_SUB_ITEMS":
+ return state.map((item) =>
+ item.hasSubitems
+ ? { ...item, Subitems: toggleSubitems(item.Subitems, action.id) }
+ : item,
+ );
+
+ case "COLLAPSE_SUB_SECOND_ITEMS":
+ return state.map((item) =>
+ item.hasSubitems
+ ? {
+ ...item,
+ Subitems: item.Subitems.map((subitem) =>
+ subitem.hasSubitems
+ ? {
+ ...subitem,
+ Subitems: toggleSubitems(subitem.Subitems, action.id),
+ }
+ : subitem,
+ ),
+ }
+ : item,
+ );
+
+ case "SELECTED":
+ return state.map((item) => selectPage(item, action.route));
+
+ default:
+ throw new Error();
+ }
+}
+
+const SidebarMenu = () => {
+ const { data: userPermissions } = usePermissions();
+ const [menuItems, dispatch] = useReducer(reducer, pageMenu);
+ const pathname = usePathname();
+ const [selectedKey, setSelectedKey] = useState(null);
+
+ useEffect(() => {
+ dispatch({ type: "SELECTED", route: pathname });
+ setSelectedKey(pathname);
+ }, [userPermissions, pathname]);
+
+ useEffect(() => {
+ if (!userPermissions) return;
+ dispatch({ type: "UPDATE_MENU", permissions: userPermissions });
+ }, [userPermissions]);
+
+ useEffect(() => {
+ selectedKey &&
+ document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+ }, [selectedKey]);
+
+ return (
+ <>
+
+ {userPermissions && (
+
+ {menuItems.map((menuItem) => {
+ return (
+
+ );
+ })}
+
+ )}
+ >
+ );
+};
+export default SidebarMenu;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx
new file mode 100644
index 0000000..e74204b
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx
@@ -0,0 +1,96 @@
+import { ExpandLess, ExpandMore } from "@mui/icons-material";
+import {
+ Box,
+ Collapse,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+ Stack,
+} from "@mui/material";
+import Link from "next/link";
+import SidebarBadge from "./SidebarBadge";
+
+const SidebarSubitems = ({ subitem, dispatch }) => {
+ return (
+ <>
+
+ {
+ if (subitem.type !== "page") {
+ dispatch({ type: "COLLAPSE_SUB_ITEMS", id: subitem.id });
+ }
+ }}
+ >
+
+ {subitem.icon}
+
+
+ {subitem.badges && (
+
+ {subitem.badges.map((badge, i) => (
+
+ ))}
+
+ )}
+ {subitem.hasSubitems ? (
+ subitem.showSubitems ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ )}
+
+
+
+ {subitem.hasSubitems ? (
+
+ {subitem.Subitems.map((subSubitem, index) => {
+ return (
+
+ );
+ })}
+
+ ) : null}
+
+ >
+ );
+};
+export default SidebarSubitems;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx
new file mode 100644
index 0000000..6fb683a
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx
@@ -0,0 +1,190 @@
+"use client";
+import ChevronRightIcon from "@mui/icons-material/ChevronRight";
+import MenuIcon from "@mui/icons-material/Menu";
+import {
+ Box,
+ Drawer,
+ IconButton,
+ Stack,
+ styled,
+ Toolbar,
+ Typography,
+ useMediaQuery,
+ useTheme,
+} from "@mui/material";
+import MuiAppBar from "@mui/material/AppBar";
+import { useState, useEffect } from "react";
+import HeaderMenu from "./HeaderMenu";
+import moment from "jalali-moment";
+import { headerMenu } from "@/core/utils/headerMenu";
+import SidebarMenu from "./Sidebar/SidebarMenu";
+
+const drawerWidth = 300;
+
+const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(
+ ({ theme, open }) => ({
+ flexGrow: 1,
+ height: "100%",
+ transition: theme.transitions.create("margin", {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ marginLeft: `-${drawerWidth}px`,
+ ...(open && {
+ transition: theme.transitions.create("margin", {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ marginLeft: 0,
+ }),
+ }),
+);
+
+const AppBar = styled(MuiAppBar, {
+ shouldForwardProp: (prop) => prop !== "open",
+})(({ theme, open }) => ({
+ transition: theme.transitions.create(["margin", "width"], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ ...(open && {
+ width: `calc(100% - ${drawerWidth}px)`,
+ marginLeft: `${drawerWidth}px`,
+ transition: theme.transitions.create(["margin", "width"], {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ }),
+}));
+
+const DrawerHeader = styled("div")(({ theme }) => ({
+ display: "flex",
+ alignItems: "center",
+ padding: theme.spacing(0, 1),
+ ...theme.mixins.toolbar,
+ minHeight: "40px !important",
+ justifyContent: "flex-end",
+}));
+
+const HeaderWithSidebar = ({ children }) => {
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down("md")); // Detect mobile/tablet screen
+ const [open, setOpen] = useState(!isMobile); // Initial state based on screen size
+
+ useEffect(() => {
+ setOpen(!isMobile); // Toggle state when screen size changes
+ }, [isMobile]);
+
+ const now = moment().locale("fa").format("YYYY/MM/DD");
+
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {headerMenu.map((menu) => (
+
+ ))}
+
+
+
+
+
+
+ تاریخ امروز: {now}
+
+
+
+
+
+
+
+ v{process.env.NEXT_PUBLIC_VERSION}
+
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export default HeaderWithSidebar;
diff --git a/src/components/login-expert/LoginExpertComponent.jsx b/src/components/login-expert/LoginExpertComponent.jsx
deleted file mode 100644
index d2a2d13..0000000
--- a/src/components/login-expert/LoginExpertComponent.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import {Box, Button, Container, Paper, Stack, TextField, Typography} from "@mui/material";
-import {Field, Formik} from "formik";
-import SvgLogin from "@/core/components/svgs/SvgLogin";
-import StyledForm from "@/core/components/StyledForm";
-import PasswordField from "@/core/components/PasswordField";
-import LoginIcon from "@mui/icons-material/Login";
-import {GET_USER_TOKEN} from "@/core/data/apiRoutes";
-import * as Yup from "yup";
-import useRequest from "@/lib/app/hooks/useRequest";
-import useUser from "@/lib/app/hooks/useUser";
-import {useTranslations} from "next-intl";
-
-const LoginExpertComponent = () => {
- const t = useTranslations();
- const requestServer = useRequest()
- const {setToken} = useUser(); // pass token to set token
- const handleSubmit = (values, props) => {
- requestServer(GET_USER_TOKEN, 'post', {
- data: {
- username: values.username,
- password: values.password,
- },
- success: {
- notification: {show: false}
- }
- }).then((response) => {
- setToken(response.data.data.token)
- }).catch(() => {
- props.setSubmitting(false)
- })
- };
- const initialValues = {
- username: "",
- password: "",
- };
- const validationSchema = Yup.object().shape({
- username: Yup.string().required(t("LoginPage.username_error_message_required")),
- password: Yup.string().required(t("LoginPage.password_error_message_required")),
- });
-
- return (
-
-
-
- {(props) => (
-
-
-
-
-
- {t("login_expert")}
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
- )
-}
-export default LoginExpertComponent
\ No newline at end of file
diff --git a/src/components/login-expert/LoginLinkRouting.jsx b/src/components/login-expert/LoginLinkRouting.jsx
deleted file mode 100644
index 1930b3c..0000000
--- a/src/components/login-expert/LoginLinkRouting.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import LinkRouting from "@/core/components/LinkRouting";
-import {Stack} from "@mui/material";
-import {useRouter} from "next/router";
-import {useTranslations} from "next-intl";
-
-const LoginLinkRouting = () => {
- const t = useTranslations();
- const router = useRouter()
- const backUrlDecodedPath = router.query?.back_url
-
- return (
-
-
- {t("LoginPage.link_routing_back_to")}{" "}
- {backUrlDecodedPath
- ? t("LoginPage.link_routing_previuos_page")
- : t("LoginPage.link_routing_main_page")}
-
-
- )
-}
-export default LoginLinkRouting
\ No newline at end of file
diff --git a/src/components/login-expert/__test__/LoginExpertComponent.test.js b/src/components/login-expert/__test__/LoginExpertComponent.test.js
deleted file mode 100644
index 695dbcb..0000000
--- a/src/components/login-expert/__test__/LoginExpertComponent.test.js
+++ /dev/null
@@ -1,154 +0,0 @@
-import {act, findByText, fireEvent, getByText, render, screen, waitFor} from '@testing-library/react';
-import MockAppWithProviders from '../../../../mocks/AppWithProvider';
-import mockRouter from 'next-router-mock'
-import LoginExpertComponent from "@/components/login-expert/LoginExpertComponent";
-import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
-
-describe('Login expert component from login page', () => {
-
- describe('Rendering', () => {
- it('LoginExpertComponent should see login expert text on the page',() => {
- render(
-
-
-
- );
- const loginExpertElement = screen.getByRole('heading', { level: 4 });
- expect(loginExpertElement).toHaveTextContent('ورود کارشناس');
- });
-
- it('LoginExpertComponent from LoginComponent Button should render login text', () => {
- render(
-
-
-
- );
- const button = screen.getByText("ورود");
- // Assertions for button props
- expect(button).toHaveAttribute('type', 'submit');
- expect(button).toHaveTextContent('ورود');
- });
-
- it("Show error when username is empty", async ()=>{
- render(
-
-
-
- );
-
- const usernameInput = screen.getByLabelText("نام کاربری")
-
- expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).not.toBeInTheDocument()
-
- fireEvent.blur(usernameInput);
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).toBeInTheDocument()
- })
-
- fireEvent.change(usernameInput, {target : {value : "testuser"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).not.toBeInTheDocument()
- })
- })
- it("Show error when password is empty", async ()=>{
- render(
-
-
-
- );
-
- const passwordInput = screen.getByLabelText("رمز عبور")
-
- expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).not.toBeInTheDocument()
-
- fireEvent.blur(passwordInput);
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).toBeInTheDocument()
- })
-
- fireEvent.change(passwordInput, {target : {value : "testuser"}})
-
- await waitFor(()=>{
- expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).not.toBeInTheDocument()
- })
- })
- });
-
- describe("Behavior", ()=>{
- it('Should fill the username field', async () => {
- render(
-
-
-
- );
- // Get username and password input elements by their name attributes
- const usernameInput = screen.getByLabelText('نام کاربری');
-
- fireEvent.change(usernameInput, {target: {value: 'testuser'}});
- await act(async ()=>{
- // Simulate user input
- expect(usernameInput).toHaveValue('testuser');
- })
- });
-
- it('Should fill the password fields', async () => {
- render(
-
-
-
- );
- // Get username and password input elements by their name attributes
- const passwordInput = screen.getByLabelText('رمز عبور');
- fireEvent.change(passwordInput, {target: {value: 'password123'}});
-
- await act(async ()=>{
- // Simulate user input
- expect(passwordInput).toHaveValue('password123');
- })
- });
-
- // this test is for when back url does not exist to run this test you should comment if in mock func
- it('Should get main page when back url dos not exist', async () => {
- render(
-
-
-
- )
- const linkElement = await screen.findByTestId("link_routing")
- expect(linkElement).toHaveTextContent("بازگشت به صفحه اصلی")
- });
-
- })
- describe("validation", ()=>{
- it("Disabled submit button until fields completed", async ()=> {
-
- render(
-
-
-
- )
- const usernameInput = screen.getByLabelText('نام کاربری');
- const passwordInput = screen.getByLabelText('رمز عبور');
- const submitButton = screen.getByText('ورود');
-
- expect(submitButton).toBeDisabled();
-
- fireEvent.change(usernameInput, {target: {value: 'testuser'}});
-
- await waitFor(async () => {
- // Now, the submit button should be enabled because both fields are completed
- expect(submitButton).toBeDisabled();
- });
-
- fireEvent.change(passwordInput, {target: {value: 'password123'}});
-
- await waitFor(async () => {
- // Now, the submit button should be enabled because both fields are completed
- expect(submitButton).toBeEnabled();
- });
- })
- })
-});
\ No newline at end of file
diff --git a/src/components/login-expert/__test__/LoginLinkRouting.test.js b/src/components/login-expert/__test__/LoginLinkRouting.test.js
deleted file mode 100644
index a63d314..0000000
--- a/src/components/login-expert/__test__/LoginLinkRouting.test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import {render, screen} from "@testing-library/react";
-import MockAppWithProviders from "../../../../mocks/AppWithProvider";
-import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
-
-describe("Login expert component from login page",()=>{
-
- describe('Rendering', () => {
- it('LoginLinkRouting from LoginComponent Should get main page when back url dos not exist', async () => {
- render(
-
-
-
- )
- const linkElement = await screen.findByTestId("link_routing")
- expect(linkElement).toHaveTextContent("بازگشت به صفحه اصلی")
- });
- })
-})
diff --git a/src/components/login-expert/index.jsx b/src/components/login-expert/index.jsx
deleted file mode 100644
index dc36d9a..0000000
--- a/src/components/login-expert/index.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
-import LoginExpertComponent from "@/components/login-expert/LoginExpertComponent";
-
-const LoginComponent = () => {
-
- return (
-
-
-
-
-
-
- );
-};
-
-export default LoginComponent;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/ActionHeader.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/ActionHeader.jsx
new file mode 100644
index 0000000..368c7b1
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/ActionHeader.jsx
@@ -0,0 +1,29 @@
+import { Stack, Typography } from "@mui/material";
+
+const ActionHeader = ({ tab }) => {
+ return (
+
+
+ .... عملیات های مربوط به تماس:
+
+
+ {tab.phone_number} ....
+
+
+ );
+};
+
+export default ActionHeader;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionCategoriesButton.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionCategoriesButton.jsx
new file mode 100644
index 0000000..c21d2dc
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionCategoriesButton.jsx
@@ -0,0 +1,27 @@
+import { Button, Grid } from "@mui/material";
+import { Controller } from "react-hook-form";
+
+const CallActionCategoriesButton = ({ category, control }) => {
+ return (
+ (
+
+ )}
+ name={"category_id"}
+ />
+ );
+};
+export default CallActionCategoriesButton;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionDescription.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionDescription.jsx
new file mode 100644
index 0000000..6eacebd
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionDescription.jsx
@@ -0,0 +1,44 @@
+import { Box, Chip, Divider, TextField } from "@mui/material";
+import { useEffect, useRef } from "react";
+import { Controller } from "react-hook-form";
+
+const CallActionDescription = ({ control }) => {
+ const inputRef = useRef(null);
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ if (inputRef.current) {
+ inputRef.current.focus();
+ }
+ }, 100);
+
+ return () => clearTimeout(timer);
+ }, []);
+
+ return (
+ <>
+
+
+
+
+ (
+
+ )}
+ name={"description"}
+ />
+
+ >
+ );
+};
+export default CallActionDescription;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionSubcategoriesButton.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionSubcategoriesButton.jsx
new file mode 100644
index 0000000..1783b32
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionSubcategoriesButton.jsx
@@ -0,0 +1,38 @@
+import { Button, Grid } from "@mui/material";
+import { useCallback } from "react";
+import { Controller, useWatch } from "react-hook-form";
+
+const CallActionSubcategoriesButton = ({ sub_category, control, onSubmit }) => {
+ const category_id = useWatch({ control, name: "category_id" });
+
+ const handleClick = useCallback(
+ (onChange) => {
+ onChange(sub_category.subcategory_id);
+ setTimeout(() => {
+ onSubmit();
+ }, 0);
+ },
+ [sub_category.subcategory_id],
+ );
+
+ return (
+ {
+ return sub_category.category_id === category_id ? (
+
+ ) : null;
+ }}
+ name={"subcategory_id"}
+ />
+ );
+};
+export default CallActionSubcategoriesButton;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsCategories.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsCategories.jsx
new file mode 100644
index 0000000..32cd698
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsCategories.jsx
@@ -0,0 +1,24 @@
+import { useCategory } from "@/lib/contexts/category";
+import CallActionCategoriesButton from "./CallActionCategoriesButton";
+import { Chip, Divider, Grid, Stack } from "@mui/material";
+
+const CallActionsCategories = ({ control }) => {
+ const { categoryLists } = useCategory();
+ return (
+ <>
+
+
+
+
+ {categoryLists.map((category) => (
+
+ ))}
+
+ >
+ );
+};
+export default CallActionsCategories;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsSubcategories.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsSubcategories.jsx
new file mode 100644
index 0000000..f67b385
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/CallActionsSubcategories.jsx
@@ -0,0 +1,27 @@
+import { useCategory } from "@/lib/contexts/category";
+import CallActionSubcategoriesButton from "./CallActionSubcategoriesButton";
+import { Chip, Divider, Grid, Stack } from "@mui/material";
+
+const CallActionsSubcategories = ({ control, onSubmit }) => {
+ const { subCategoryLists } = useCategory();
+ return (
+ <>
+
+
+
+
+ {subCategoryLists.map((sub_category, index) => {
+ return (
+
+ );
+ })}
+
+ >
+ );
+};
+export default CallActionsSubcategories;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallActions/index.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/index.jsx
new file mode 100644
index 0000000..aa011ae
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallActions/index.jsx
@@ -0,0 +1,71 @@
+import StyledForm from "@/core/components/StyledForm";
+import { CALL_ACTION } from "@/core/utils/routes";
+import { useCall } from "@/lib/contexts/call";
+import useRequest from "@/lib/hooks/useRequest";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { Stack } from "@mui/material";
+import { useForm } from "react-hook-form";
+import { object, string } from "yup";
+import ActionHeader from "./ActionHeader";
+import CallActionDescription from "./CallActionDescription";
+import CallActionsCategories from "./CallActionsCategories";
+import CallActionsSubcategories from "./CallActionsSubcategories";
+
+const defaultValues = {
+ description: "",
+ category_id: "",
+ subcategory_id: "",
+};
+
+const validationSchema = object({
+ category_id: string().required("لطفا نام کاربری را وارد کنید!"),
+ subcategory_id: string().required("لطفا رمز عبور را وارد کنید!"),
+});
+
+function CallActions({ tab }) {
+ const requestServer = useRequest();
+ const { closeCall } = useCall();
+
+ const {
+ control,
+ handleSubmit,
+ formState: { isSubmitting },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(validationSchema),
+ mode: "all",
+ });
+
+ const onSubmit = handleSubmit(async (data) => {
+ try {
+ const formData = new FormData();
+ data.description != "" &&
+ formData.append("description", data.description);
+ formData.append("category_id", data.category_id);
+ formData.append("subcategory_id", data.subcategory_id);
+ await requestServer(`${CALL_ACTION}/${tab.id}`, "post", {
+ data: formData,
+ });
+ closeCall(tab.id);
+ } catch (error) {
+ console.error("Login error:", error);
+ }
+ });
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default CallActions;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty.jsx
new file mode 100644
index 0000000..e76a269
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ErrorOrEmpty.jsx
@@ -0,0 +1,39 @@
+import { Typography } from "@mui/material";
+
+const ErrorOrEmpty = ({ isErrorOrEmpty }) => {
+ return (
+ <>
+ {isErrorOrEmpty === "error" ? (
+
+ خطا در دریافت تاریخچه تماس دریافتی
+
+ ) : isErrorOrEmpty === "empty" ? (
+
+ تاریخچه ای برای تماس دریافتی یافت نشد
+
+ ) : (
+ <>>
+ )}
+ >
+ );
+};
+
+export default ErrorOrEmpty;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/HistoryHeader.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/HistoryHeader.jsx
new file mode 100644
index 0000000..e3498d1
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/HistoryHeader.jsx
@@ -0,0 +1,25 @@
+import { Stack, Typography } from "@mui/material";
+
+const HistoryHeader = ({ tab }) => {
+ return (
+
+
+ .... تاریخچه تماس های:
+
+
+ {tab.phone_number} ....
+
+
+ );
+};
+
+export default HistoryHeader;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData.jsx
new file mode 100644
index 0000000..5197ca8
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/PreviousOperatorData.jsx
@@ -0,0 +1,30 @@
+import HeadsetMicIcon from "@mui/icons-material/HeadsetMic";
+import { Avatar, Box, Stack, Typography } from "@mui/material";
+import moment from "jalali-moment";
+
+const PreviousOperatorData = ({ historyItem }) => {
+ return (
+
+
+
+
+
+
+
+
+
+ {historyItem.operator_full_name}
+
+
+ (کارشناس)
+
+
+
+ {moment(historyItem.created_at).locale("fa").fromNow()}
+
+
+
+ );
+};
+
+export default PreviousOperatorData;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics..jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics..jsx
new file mode 100644
index 0000000..13e7063
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/Topics..jsx
@@ -0,0 +1,60 @@
+import { Chip, Divider, Stack } from "@mui/material";
+
+const Topics = ({ historyItem }) => {
+ return (
+
+
+
+
+ {historyItem.category_name && (
+
+ )}
+
+
+
+
+ {historyItem.subcategory_name && (
+
+ )}
+
+
+
+
+ {historyItem.description && }
+
+
+ );
+};
+
+export default Topics;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx
new file mode 100644
index 0000000..f06ba45
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/ListItemOfCalls/index.jsx
@@ -0,0 +1,14 @@
+import { Stack } from "@mui/material";
+import PreviousOperatorData from "./PreviousOperatorData";
+import Topics from "./Topics.";
+
+const ListItemOfCalls = ({ historyItem }) => {
+ return (
+
+
+
+
+ );
+};
+
+export default ListItemOfCalls;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/LoadingHistory.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/LoadingHistory.jsx
new file mode 100644
index 0000000..674b7eb
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/LoadingHistory.jsx
@@ -0,0 +1,115 @@
+import {
+ Box,
+ List,
+ ListItem,
+ ListItemAvatar,
+ ListItemText,
+ Skeleton,
+} from "@mui/material";
+
+const LoadingHistory = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+ }
+ secondary={
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default LoadingHistory;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/index.jsx b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/index.jsx
new file mode 100644
index 0000000..77e7263
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/CallHistory/index.jsx
@@ -0,0 +1,61 @@
+import useCallerHistory from "@/lib/hooks/useCallerHistory";
+import { Box, Chip, Divider, Fade, List, Stack } from "@mui/material";
+import { useState } from "react";
+import HistoryHeader from "./HistoryHeader";
+import LoadingHistory from "./LoadingHistory";
+import ErrorOrEmpty from "./ErrorOrEmpty";
+import ListItemOfCalls from "./ListItemOfCalls";
+import { Headphones } from "@mui/icons-material";
+
+const max_size = 10;
+const CallHistory = ({ tab }) => {
+ const {
+ firstItemOfHistory,
+ historyList,
+ isLoadingHistoryList,
+ errorHistoryList,
+ } = useCallerHistory(tab.id, tab.phone_number, max_size);
+ const [showRestOfHistory, setShowRestOfHistory] = useState(false);
+
+ return (
+
+
+
+ {isLoadingHistoryList ? (
+
+ ) : errorHistoryList ? (
+
+ ) : !firstItemOfHistory ? (
+
+ ) : (
+
+
+ {historyList && (
+
+ }
+ onClick={() => setShowRestOfHistory(true)}
+ label={"نمایش موارد بیشتر"}
+ disabled={showRestOfHistory}
+ />
+
+ )}
+ {showRestOfHistory &&
+ historyList.map((historyItem, index) => (
+ <>
+
+
+ >
+ ))}
+
+ )}
+
+
+ );
+};
+
+export default CallHistory;
diff --git a/src/components/widget/call/CallTabs/CallTabPanel/index.jsx b/src/components/widget/call/CallTabs/CallTabPanel/index.jsx
new file mode 100644
index 0000000..a22af79
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabPanel/index.jsx
@@ -0,0 +1,29 @@
+import { Box, Divider, Stack } from "@mui/material";
+import CallActions from "./CallActions";
+import CallHistory from "./CallHistory";
+
+const CallTabPanel = ({ tab }) => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CallTabPanel;
diff --git a/src/components/widget/call/CallTabs/CallTabsList/CallTabDetails.jsx b/src/components/widget/call/CallTabs/CallTabsList/CallTabDetails.jsx
new file mode 100644
index 0000000..a7c0290
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabsList/CallTabDetails.jsx
@@ -0,0 +1,21 @@
+import { Call } from "@mui/icons-material";
+import { Stack, Typography } from "@mui/material";
+import CallTabTime from "./CallTabTime";
+
+const CallTabDetails = ({ tab }) => {
+ return (
+
+
+
+ {tab.phone_number}
+
+
+
+ );
+};
+export default CallTabDetails;
diff --git a/src/components/widget/call/CallTabs/CallTabsList/CallTabLabel.jsx b/src/components/widget/call/CallTabs/CallTabsList/CallTabLabel.jsx
new file mode 100644
index 0000000..3b45b80
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabsList/CallTabLabel.jsx
@@ -0,0 +1,35 @@
+import { useCall } from "@/lib/contexts/call";
+import { Close } from "@mui/icons-material";
+import { IconButton, Stack, Zoom } from "@mui/material";
+import CallTabDetails from "./CallTabDetails";
+
+const CallTabLabel = ({ tab, index }) => {
+ const { closeCall, activeCall } = useCall();
+ const handleCloseClick = (id) => {
+ closeCall(id);
+ };
+
+ return (
+
+
+
+ handleCloseClick(tab.id)}>
+
+
+
+
+ );
+};
+
+export default CallTabLabel;
diff --git a/src/components/widget/call/CallTabs/CallTabsList/CallTabTime.jsx b/src/components/widget/call/CallTabs/CallTabsList/CallTabTime.jsx
new file mode 100644
index 0000000..a2ce2b3
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabsList/CallTabTime.jsx
@@ -0,0 +1,28 @@
+import { Typography } from "@mui/material";
+import moment from "jalali-moment";
+import { useEffect, useState } from "react";
+
+const CallTabTime = ({ realTimeDate }) => {
+ const [date, setDate] = useState("...");
+ const changeTabTime = (tabTime) => {
+ moment.relativeTimeThreshold("ss", 1);
+ return moment(tabTime).locale("fa").fromNow();
+ };
+
+ useEffect(() => {
+ const timer = setInterval(() => {
+ setDate(changeTabTime(realTimeDate));
+ }, 1000);
+
+ return () => {
+ clearInterval(timer);
+ };
+ }, [realTimeDate]);
+
+ return (
+
+ {date}
+
+ );
+};
+export default CallTabTime;
diff --git a/src/components/widget/call/CallTabs/CallTabsList/index.jsx b/src/components/widget/call/CallTabs/CallTabsList/index.jsx
new file mode 100644
index 0000000..67e02d9
--- /dev/null
+++ b/src/components/widget/call/CallTabs/CallTabsList/index.jsx
@@ -0,0 +1,40 @@
+import { useCall } from "@/lib/contexts/call";
+import { Box, Tab, Tabs } from "@mui/material";
+import CallTabLabel from "./CallTabLabel";
+
+const CallTabsList = () => {
+ const { calls, changeActiveTabCall, activeCall } = useCall();
+ const handleChange = (event, newValue) => {
+ changeActiveTabCall(newValue);
+ };
+
+ return (
+
+
+ {calls.map((call, index) => (
+ }
+ key={call.id}
+ />
+ ))}
+
+
+ );
+};
+
+export default CallTabsList;
diff --git a/src/components/widget/call/CallTabs/index.jsx b/src/components/widget/call/CallTabs/index.jsx
new file mode 100644
index 0000000..58bb4e7
--- /dev/null
+++ b/src/components/widget/call/CallTabs/index.jsx
@@ -0,0 +1,17 @@
+import { useCall } from "@/lib/contexts/call";
+import CallTabPanel from "./CallTabPanel";
+import CallTabsList from "./CallTabsList";
+
+const CallTabs = () => {
+ const { calls } = useCall();
+
+ return (
+ <>
+
+ {calls.map((call) => (
+
+ ))}
+ >
+ );
+};
+export default CallTabs;
diff --git a/src/components/widget/call/CallWidgetDialog.jsx b/src/components/widget/call/CallWidgetDialog.jsx
new file mode 100644
index 0000000..ea29f13
--- /dev/null
+++ b/src/components/widget/call/CallWidgetDialog.jsx
@@ -0,0 +1,48 @@
+"use client";
+import { DialogTransition } from "@/core/components/DialogTransition";
+import { useCall } from "@/lib/contexts/call";
+import { useSocket } from "@/lib/contexts/socket";
+import { Dialog } from "@mui/material";
+import { useEffect } from "react";
+import CallTabs from "./CallTabs";
+
+const CallWidgetDialog = () => {
+ const { openCallDialog, setOpenCallDialog, calls, newCall } = useCall();
+ const { socket } = useSocket();
+
+ useEffect(() => {
+ const call = (_data, act) => {
+ const data = JSON.parse(_data);
+ newCall({
+ id: data.call_id,
+ phone_number: data.phone_number,
+ });
+ act();
+ };
+ socket.on("call", call);
+
+ return () => {
+ socket.off("call", call);
+ };
+ });
+
+ useEffect(() => {
+ if (calls.length === 0) {
+ setOpenCallDialog(false);
+ return;
+ }
+ setOpenCallDialog(true);
+ }, [calls.length]);
+
+ return (
+
+ );
+};
+
+export default CallWidgetDialog;
diff --git a/src/components/widget/call/index.jsx b/src/components/widget/call/index.jsx
new file mode 100644
index 0000000..51280d3
--- /dev/null
+++ b/src/components/widget/call/index.jsx
@@ -0,0 +1,29 @@
+"use client";
+import { CallProvider } from "@/lib/contexts/call";
+import { CategoriesProvider } from "@/lib/contexts/category";
+import { useSocket } from "@/lib/contexts/socket";
+import { useEffect } from "react";
+import CallWidgetDialog from "./CallWidgetDialog";
+
+const CallWidget = () => {
+ const { socket, status } = useSocket();
+
+ useEffect(() => {
+ if (status == "connected") return;
+
+ socket.connect();
+
+ return () => {
+ socket.disconnect();
+ };
+ }, [socket]);
+
+ return (
+
+
+
+
+
+ );
+};
+export default CallWidget;
diff --git a/src/core/components/AvatarUpload.jsx b/src/core/components/AvatarUpload.jsx
deleted file mode 100644
index 03a9cba..0000000
--- a/src/core/components/AvatarUpload.jsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import {Avatar, Box, TextField} from "@mui/material";
-import {useState} from "react";
-import DeleteIcon from "@mui/icons-material/Delete";
-import AddIcon from "@mui/icons-material/Add";
-
-const AvatarUpload = ({user, setFieldValue, valueAvatar, changeFlag}) => {
- const [selectedImage, setSelectedImage] = useState(user.expert_avatar);
- const [isHovered, setIsHovered] = useState(false);
-
- const handleImageChange = (event) => {
- const newImage = event.target?.files?.[0];
- if (newImage) {
- setSelectedImage(URL.createObjectURL(newImage));
- setFieldValue(valueAvatar, newImage);
- setFieldValue(changeFlag, true);
- } else {
- setSelectedImage("");
- setFieldValue(valueAvatar, null);
- }
- };
-
- const handleDeleteImage = () => {
- setSelectedImage("");
- setFieldValue(valueAvatar, null);
- setFieldValue(changeFlag, true);
- };
-
- const handleMouseEnter = () => {
- setIsHovered(true);
- };
-
- const handleMouseLeave = () => {
- setIsHovered(false);
- };
-
- return (
-
-
-
-
- {isHovered && (
-
- {selectedImage ? (
-
- ) : (
-
- )}
-
- )}
-
-
-
-
- );
-};
-
-export default AvatarUpload;
diff --git a/src/core/components/DataTable.jsx b/src/core/components/DataTable.jsx
deleted file mode 100644
index 41bdbaa..0000000
--- a/src/core/components/DataTable.jsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import {useTranslations} from "next-intl";
-import useLanguage from "@/lib/app/hooks/useLanguage";
-import {useEffect, useMemo, useState} from "react";
-import moment from "moment-jalaali";
-import useSWR from "swr";
-import {Typography} from "@mui/material";
-import MaterialReactTable from "material-react-table";
-import useRequest from "@/lib/app/hooks/useRequest";
-
-function DataTable(props) {
- const requestServer = useRequest({auth: true})
- const t = useTranslations();
- const {languageApp, languageList} = useLanguage();
- const [columnFilters, setColumnFilters] = useState([]);
- const [sorting, setSorting] = useState([]);
- const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
- const [columnFilterFns, setColumnFilterFns] = useState(() => {
- let output = {};
- const list = props.columns.map((item) =>
- item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""}
- );
- for (const key in list) {
- const nestedObj = list[key];
- for (const nestedKey in nestedObj) {
- output[nestedKey] = nestedObj[nestedKey];
- }
- }
- return output;
- });
-
- const [updateTime, setUpdateTime] = useState(
- moment().format("HH:mm | jYYYY/jMM/jDD")
- );
-
- const tableLocalization = useMemo(
- () =>
- languageList.find((item) => item.key === languageApp).tableLocalization,
- [languageApp, languageList]
- );
-
- const fetchUrl = useMemo(() => {
- const params = new URLSearchParams();
- params.set(
- "start",
- `${pagination.pageIndex * pagination.pageSize}`
- );
- const filters = columnFilters.map((filter) => {
- let datatype;
- for (const i in props.columns) {
- if (props.columns[i].id === filter.id) {
- datatype = props.columns[i].datatype;
- }
- }
- return {
- ...filter,
- fn: columnFilterFns[filter.id],
- datatype: datatype,
- };
- });
- params.set("size", pagination.pageSize);
- params.set("filters", JSON.stringify(filters ?? []));
- params.set("sorting", JSON.stringify(sorting ?? []));
- return `${props.tableUrl}?${params}`;
- }, [
- props.tableUrl,
- columnFilters,
- columnFilterFns,
- pagination,
- sorting,
- props.columns,
- ]);
-
- const {data, isValidating, mutate} = useSWR(fetchUrl, (...args) =>
- requestServer(args, 'get', {
- pending: false,
- success: {notification: {show: false}}
- }).then((response) => response.data).catch(() => {
- })
- , {
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: true,
- keepPreviousData: true
- });
-
- useEffect(() => {
- setUpdateTime(moment().format("HH:mm | jYYYY/jMM/jDD"));
- }, [isValidating, languageApp]);
-
- return (
- (
- <>
- {props.enableCustomToolbar /* send condition */
- ? /* send component */
- : ""}
- >
- )}
- renderBottomToolbarCustomActions={({table}) => (
- <>
- {props.enableLastUpdate /* send condition */ ? (
-
- {t("last_updated_at")}: {updateTime}
-
- ) : (
- ""
- )}
- >
- )}
- state={{
- showProgressBars: isValidating,
- columnFilters,
- columnFilterFns,
- pagination,
- sorting,
- }}
- positionActionsColumn={"last"}
- enableRowActions={props.enableRowActions}
- renderRowActions={({row}) => }
- {...props}
- />
- );
-}
-
-export default DataTable;
\ No newline at end of file
diff --git a/src/core/components/DialogTransition.jsx b/src/core/components/DialogTransition.jsx
index d94765f..de09a75 100644
--- a/src/core/components/DialogTransition.jsx
+++ b/src/core/components/DialogTransition.jsx
@@ -1,6 +1,8 @@
-import {forwardRef} from "react";
-import {Slide} from "@mui/material";
+import { forwardRef } from "react";
+import { Slide } from "@mui/material";
-export const DialogTransition = forwardRef(function DialogTransition(props, ref) {
- return ;
-});
+export const DialogTransition = forwardRef(
+ function DialogTransition(props, ref) {
+ return ;
+ },
+);
diff --git a/src/core/components/GlobalHead.jsx b/src/core/components/GlobalHead.jsx
deleted file mode 100644
index 5d6186d..0000000
--- a/src/core/components/GlobalHead.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import Head from "next/head";
-
-const GlobalHead = () => {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default GlobalHead
\ No newline at end of file
diff --git a/src/core/components/ImageConvertor.jsx b/src/core/components/ImageConvertor.jsx
deleted file mode 100644
index 9f99bc1..0000000
--- a/src/core/components/ImageConvertor.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import ImageResize from "image-resize";
-
-const ImageResizer = async (image) => {
- const imageResize = new ImageResize({
- quality: 1,
- format: "jpg",
- outputType: "base64",
- width: 400,
- });
-
- const get = await imageResize.get(image);
- const resize = await imageResize.resize(get).then();
- const output = await imageResize.output(resize).then();
-
- const avatar = await (await import("image-to-file-converter"))
- .base64ToFile(output)
- .then();
-
- return avatar;
-};
-
-export default ImageResizer;
diff --git a/src/core/components/LinkRouting.jsx b/src/core/components/LinkRouting.jsx
deleted file mode 100644
index f8fac0a..0000000
--- a/src/core/components/LinkRouting.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import MuiLink from "@mui/material/Link";
-import {styled} from "@mui/material/styles";
-import clsx from "clsx";
-import NextLink from "next/link";
-import {useRouter} from "next/router";
-import * as React from "react";
-
-// Add support for the sx prop for consistency with the other branches.
-const Anchor = styled("a")({});
-
-export const NextLinkComposed = React.forwardRef(function NextLinkComposed(
- props,
- ref
-) {
- const {
- to,
- linkAs,
- replace,
- scroll,
- shallow,
- prefetch,
- legacyBehavior = true,
- locale,
- ...other
- } = props;
-
- return (
-
-
-
- );
-});
-
-// A styled version of the Next.js Link component:
-// https://nextjs.org/docs/api-reference/next/link
-const LinkRouting = React.forwardRef(function Link(props, ref) {
- const {
- activeClassName = "active",
- as,
- className: classNameProps,
- href,
- legacyBehavior,
- linkAs: linkAsProp,
- locale,
- noLinkStyle,
- prefetch,
- replace,
- role, // Link don't have roles.
- scroll,
- shallow,
- ...other
- } = props;
-
- const router = useRouter();
- const pathname = typeof href === "string" ? href : href.pathname;
- const className = clsx(classNameProps, {
- [activeClassName]: router.pathname === pathname && activeClassName,
- });
-
- const isExternal =
- typeof href === "string" &&
- (href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);
-
- if (isExternal) {
- if (noLinkStyle) {
- return ;
- }
-
- return ;
- }
-
- const linkAs = linkAsProp || as;
- const nextjsProps = {
- to: href,
- linkAs,
- replace,
- scroll,
- shallow,
- prefetch,
- legacyBehavior,
- locale,
- };
-
- if (noLinkStyle) {
- return (
-
- );
- }
-
- return (
-
- );
-});
-
-export default LinkRouting;
diff --git a/src/core/components/LoadingHardPage.jsx b/src/core/components/LoadingHardPage.jsx
index 5d00cd0..4e9125a 100644
--- a/src/core/components/LoadingHardPage.jsx
+++ b/src/core/components/LoadingHardPage.jsx
@@ -1,43 +1,82 @@
+"use client";
+import SvgError from "@/core/components/svgs/SvgError";
import SvgLoading from "@/core/components/svgs/SvgLoading";
-import {Backdrop, Box} from "@mui/material";
-import {styled} from "@mui/material/styles";
+import { Backdrop, Box, Stack, styled, useTheme } from "@mui/material";
const LoadingImage = styled(Box)({
- "@keyframes load": {
- "0%": {
- // opacity: 0,
- transform: "scale(1)",
- },
- "50%": {
- // opacity: 1,
- transform: "scale(2)",
- },
- "100%": {
- // opacity: 0,
- transform: "scale(1)",
- },
+ "@keyframes load": {
+ "0%": {
+ transform: "scale(1)",
},
- animation: "load 2s infinite",
+ "50%": {
+ transform: "scale(.5)",
+ },
+ "100%": {
+ transform: "scale(1)",
+ },
+ },
+ animation: "load 2s infinite",
});
-const LoadingHardPage = ({children, loading}) => {
- return (
- <>
- theme.zIndex.modal + 1}}
- open={loading}
- >
- {
+ const theme = useTheme();
+ return (
+ <>
+ theme.zIndex.drawer + 1,
+ ...sx,
+ }}
+ open={loading}
+ >
+
+ {authState ? (
+
+ {icon ? (
+
-
-
-
- {children}
- >
- );
+ {icon}
+
+ ) : (
+
+ )}
+
+ ) : (
+
+ {icon ? (
+
+ {icon}
+
+ ) : (
+
+ )}
+
+ )}
+
+ {label}
+
+
+
+ {children}
+ >
+ );
};
export default LoadingHardPage;
diff --git a/src/core/components/LtrTextField.jsx b/src/core/components/LtrTextField.jsx
new file mode 100644
index 0000000..fd58d17
--- /dev/null
+++ b/src/core/components/LtrTextField.jsx
@@ -0,0 +1,10 @@
+import { styled, TextField } from "@mui/material";
+
+const LtrTextField = styled(TextField)`
+ .MuiInputBase-input {
+ /* @noflip */
+ direction: ltr;
+ }
+`;
+
+export default LtrTextField;
diff --git a/src/core/components/Messages.jsx b/src/core/components/Messages.jsx
deleted file mode 100644
index 8a5cfc9..0000000
--- a/src/core/components/Messages.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import CenterLayout from "@/layouts/CenterLayout";
-import FullPageLayout from "@/layouts/FullPageLayout";
-import SvgLoading from "@/core/components/svgs/SvgLoading";
-
-const Message = ({text, actions}) => {
- return (
-
-
-
- {text}
- {actions}
-
-
- );
-};
-
-export default Message;
diff --git a/src/core/components/Middleware/RolePermissionComponent.jsx b/src/core/components/Middleware/RolePermissionComponent.jsx
deleted file mode 100644
index 869f78a..0000000
--- a/src/core/components/Middleware/RolePermissionComponent.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Button, Typography } from "@mui/material";
-import { useTranslations } from "next-intl";
-import { NextLinkComposed } from "@/core/components/LinkRouting";
-import Message from "@/core/components/Messages";
-
-const RolePermissionComponent = () => {
- const t = useTranslations();
-
- return (
-
- {t("Permission.typography_you_dont_have_access")}
-
- }
- actions={
- <>
-
- >
- }
- />
- );
-};
-
-export default RolePermissionComponent;
diff --git a/src/core/components/Middleware/WithAuthComponent.jsx b/src/core/components/Middleware/WithAuthComponent.jsx
deleted file mode 100644
index 9a6ff5d..0000000
--- a/src/core/components/Middleware/WithAuthComponent.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Button, Typography } from "@mui/material";
-import { useRouter } from "next/router";
-import Message from "@/core/components/Messages";
-import { NextLinkComposed } from "@/core/components/LinkRouting";
-import {useTranslations} from "next-intl";
-
-const WithAuthComponent = () => {
- const router = useRouter();
- const t = useTranslations();
-
- return (
-
- {t("Authorization.typography_your_access_to_this_page_has_expired_Please_login_again")}
-
- }
- actions={
- <>
-
- >
- }
- />
- );
-};
-
-export default WithAuthComponent;
diff --git a/src/core/components/Middleware/WithoutAuthComponent.jsx b/src/core/components/Middleware/WithoutAuthComponent.jsx
deleted file mode 100644
index 7dbb38d..0000000
--- a/src/core/components/Middleware/WithoutAuthComponent.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {Button, Stack, Typography} from "@mui/material";
-import Message from "@/core/components/Messages";
-import {useTranslations} from "next-intl";
-const WithoutAuthComponent = ({ backUrlDecodedPath }) => {
- const t = useTranslations();
-
- return (
-
-
- {t("Authorization.typography_your_login_is_valid_and_you_do_not_need_to_login_again")}
-
-
- {t("Authorization.typography_redirect_to")}{" "}
- {backUrlDecodedPath
- ? t("Authorization.typography_routing_previuos_page")
- : t("Authorization.typography_routing_dashbaord_page")}
-
-
- }
- />
- );
-};
-export default WithoutAuthComponent;
diff --git a/src/core/components/Middleware/__test__/RolePermissionComponent.test.js b/src/core/components/Middleware/__test__/RolePermissionComponent.test.js
deleted file mode 100644
index 44a583d..0000000
--- a/src/core/components/Middleware/__test__/RolePermissionComponent.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
-import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
-
-describe('RolePermissionComponent From RolePermissionComponent page', () => {
- describe('Rendering', () => {
- it('should render the error message when user dont have permission', () => {
- render();
-
- expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
-
- });
-
- it('should render the back dashboard button when user dont have permission', () => {
- render();
-
- const backButton = screen.queryByText('بازگشت به صفحه اصلی');
-
- expect(backButton).toBeInTheDocument();
-
- });
- });
-});
diff --git a/src/core/components/Middleware/__test__/WithAuthComponent.test.js b/src/core/components/Middleware/__test__/WithAuthComponent.test.js
deleted file mode 100644
index a43e20f..0000000
--- a/src/core/components/Middleware/__test__/WithAuthComponent.test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { render, screen, fireEvent, waitFor } from '@testing-library/react';
-import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
-import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
-import mockRouter from 'next-router-mock';
-
-describe('WithAuthComponent From WithAuthMiddleware', () => {
- describe('Rendering', () => {
- it('should see expired text in render component', () => {
- render();
-
- const authText = screen.queryByText('دسترسی شما منقضی شده است لطفا دوباره ورود نمایید.');
-
- expect(authText).toBeInTheDocument();
- });
-
- it('should see login button in render component', () => {
- render();
-
- const loginButton = screen.queryByText('ورود');
-
- expect(loginButton).toBeInTheDocument();
- });
- });
- describe('behavior', () => {
- it('should see if router updated in login button', () => {
-
- mockRouter.query.back_url = 'back_url'
- render();
-
- const loginButton = screen.queryByText('ورود');
-
- fireEvent.click(loginButton);
-
- expect(mockRouter).toMatchObject({
- query: { back_url: "back_url" },
- });
- });
- });
-});
diff --git a/src/core/components/Middleware/__test__/WithoutAuthComponent.test.js b/src/core/components/Middleware/__test__/WithoutAuthComponent.test.js
deleted file mode 100644
index 520d7bd..0000000
--- a/src/core/components/Middleware/__test__/WithoutAuthComponent.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import {render, screen, waitFor} from '@testing-library/react';
-import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
-import MockAppWithProviders from "../../../../../mocks/AppWithProvider";
-import WithoutAuthMiddleware from "@/middlewares/WithoutAuth";
-
-describe('WithoutAuthComponent From WithoutAuthMiddleware', () => {
- describe('Rendering', () => {
- it('should render the message with correct text when backUrlDecodedPath is not provided', async () => {
-
- localStorage.setItem("_token", 'token');
-
- render();
-
- await waitFor(()=>{
- expect(screen.queryByText('شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.')).toBeInTheDocument();
-
- expect(screen.queryByText('درحال رفتن به صفحه داشبورد...')).toBeInTheDocument();
- })
-
- });
-
- it('should render the message with a different text when backUrlDecodedPath is provided', async() => {
- render();
-
- localStorage.setItem("_token", 'token');
-
- render();
-
- await waitFor(()=>{
-
- expect(screen.queryByText('درحال رفتن به صفحه قبل...')).toBeInTheDocument();
- })
-
-
- });
- });
-});
diff --git a/src/core/components/MuiDatePicker.jsx b/src/core/components/MuiDatePicker.jsx
deleted file mode 100644
index 18be3cc..0000000
--- a/src/core/components/MuiDatePicker.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import {LocalizationProvider, MobileDateTimePicker} from "@mui/x-date-pickers";
-import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali";
-import moment from "jalali-moment";
-import {faIR} from "@mui/x-date-pickers/locales";
-import {Box, IconButton} from "@mui/material";
-import ClearIcon from "@mui/icons-material/Clear";
-import {useTranslations} from "next-intl";
-
-export default function MuiDatePicker({column}) {
- const t = useTranslations();
- const filterFnValue = column.columnDef._filterFn;
-
- return (
-
-
- {
- const date = new Date(newValue);
- const formattedDate = moment(date)
- .locale("en")
- .format("YYYY-MM-DD HH:mm");
- column.setFilterValue(formattedDate);
- }}
- slotProps={{
- textField: {
- placeholder: "تاریخ خود را وارد کنید",
- helperText: `${t("filter_mode")}: ${t(filterFnValue)}`,
- sx: {minWidth: "120px"},
- variant: "standard",
- },
- }}
- value={
- column.getFilterValue()
- ? new Date(column.getFilterValue())
- : null
- }
- />
-
- {
- column.setFilterValue(null);
- }}
- sx={{
- color: column.getFilterValue()
- ? "rgba(0, 0, 0, 0.54)"
- : "#bfbfbf",
- }}
- >
-
-
-
- );
-}
diff --git a/src/core/components/NetworkComponent.jsx b/src/core/components/NetworkComponent.jsx
deleted file mode 100644
index 9610b1c..0000000
--- a/src/core/components/NetworkComponent.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import useNetwork from "@/lib/app/hooks/useNetwork";
-import {useEffect, useRef} from "react";
-import {toast} from "react-toastify";
-import WifiIcon from '@mui/icons-material/Wifi';
-import WifiOffIcon from '@mui/icons-material/WifiOff';
-import {useTranslations} from "next-intl";
-
-const NetworkComponent = () => {
- const networkToastId = useRef(null);
- const network = useNetwork()
- const t = useTranslations()
-
- useEffect(() => {
- if (network.online) {
- toast.update(networkToastId.current, {
- type: toast.TYPE.SUCCESS,
- render: t('online_message'),
- autoClose: 2000,
- closeButton: true,
- closeOnClick: true,
- icon:
- });
- return
- }
- networkToastId.current = toast.warn(t('offline_message'), {
- containerId: 'connection',
- draggable: false,
- autoClose: false, closeButton: false, closeOnClick: false, icon:
- })
- }, [network.online]);
-
- return ''
-}
-
-export default NetworkComponent
\ No newline at end of file
diff --git a/src/core/components/NoSsrHandler.jsx b/src/core/components/NoSsrHandler.jsx
deleted file mode 100644
index 5a4c4e1..0000000
--- a/src/core/components/NoSsrHandler.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import {NoSsr} from "@mui/material";
-
-const NoSsrHandler = ({isBot, children}) => {
- if (isBot) return children;
- return {children};
-};
-
-export default NoSsrHandler;
diff --git a/src/core/components/PageLoading.jsx b/src/core/components/PageLoading.jsx
new file mode 100644
index 0000000..5b36836
--- /dev/null
+++ b/src/core/components/PageLoading.jsx
@@ -0,0 +1,25 @@
+"use client";
+import { Paper } from "@mui/material";
+import LoadingHardPage from "./LoadingHardPage";
+
+const PageLoading = () => {
+ return (
+
+
+
+ );
+};
+export default PageLoading;
diff --git a/src/core/components/PasswordField/__test__/index.test.js b/src/core/components/PasswordField/__test__/index.test.js
deleted file mode 100644
index 479f91f..0000000
--- a/src/core/components/PasswordField/__test__/index.test.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import {fireEvent, getByRole, render, screen} from "@testing-library/react";
-import PasswordField from "@/core/components/PasswordField";
-import {Formik} from "formik";
-
-describe('Password Field component in core folder', () => {
- describe('Rendering', () => {
- it('Show password when visibility icon clicked',() => {
- render (
- {}}>
- {(props)=>(
-
- )}
-
- )
-
- const iconElement = screen.getByLabelText("رمز عبور")
- const iconButton = screen.getByRole("button")
-
-
- expect(iconElement).toHaveAttribute('type', 'password');
-
- fireEvent.click(iconButton);
-
- expect(iconElement).toHaveAttribute("type", "text");
-
- fireEvent.click(iconButton);
-
- expect(iconElement).toHaveAttribute('type', 'password');
- })
- })
-})
\ No newline at end of file
diff --git a/src/core/components/PasswordField/index.jsx b/src/core/components/PasswordField/index.jsx
deleted file mode 100644
index d109b73..0000000
--- a/src/core/components/PasswordField/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {useState} from "react";
-import {IconButton, InputAdornment, TextField} from "@mui/material";
-import {Visibility, VisibilityOff} from "@mui/icons-material";
-import {Field} from "formik";
-
-const PasswordField = (props) => {
- const [showPassword, setShowPassword] = useState(false);
-
- const handleClickShowPassword = () => {
- setShowPassword(!showPassword);
- };
-
- return (
-
-
- {showPassword ? : }
-
-
- ),
- }}
- />
- );
-};
-
-export default PasswordField;
diff --git a/src/core/components/PriceField.jsx b/src/core/components/PriceField.jsx
deleted file mode 100644
index 29d8763..0000000
--- a/src/core/components/PriceField.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import {InputAdornment, TextField, Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-
-const PriceField = (props) => {
- const t = useTranslations();
- return (
-
- {((props.value) / 10).toLocaleString()}
- {t("ConfirmDialog.toman")}
-
- ),
- }}
- {...props}
- />
- )
-}
-export default PriceField
\ No newline at end of file
diff --git a/src/core/components/Profile/ProfileActions.jsx b/src/core/components/Profile/ProfileActions.jsx
new file mode 100644
index 0000000..eeb500c
--- /dev/null
+++ b/src/core/components/Profile/ProfileActions.jsx
@@ -0,0 +1,73 @@
+"use client";
+import { GET_USER_LOGOUT_ROUTE, LOGOUT_USER_ROUTE } from "@/core/utils/routes";
+import { useAuth } from "@/lib/contexts/auth";
+import useRequest from "@/lib/hooks/useRequest";
+import ModeEditIcon from "@mui/icons-material/ModeEdit";
+import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew";
+import VpnKeyIcon from "@mui/icons-material/VpnKey";
+import { Box, Divider, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+
+const ProfileActions = () => {
+ const { getUser, logout } = useAuth();
+ const requestServer = useRequest();
+ const [openUpdate, setOpenUpdate] = useState(false);
+ const [openChangePass, setOpenChangePass] = useState(false);
+
+ const openUpdateProfile = () => {
+ getUser();
+ setOpenUpdate(true);
+ };
+ const handleLogout = () => {
+ requestServer(GET_USER_LOGOUT_ROUTE, "post").then(() => {
+ logout();
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setOpenChangePass(true);
+ }}
+ >
+
+
+
+
+ {/*
+ */}
+ >
+ );
+};
+export default ProfileActions;
diff --git a/src/core/components/Profile/ProfileInfo.jsx b/src/core/components/Profile/ProfileInfo.jsx
new file mode 100644
index 0000000..ec84b2a
--- /dev/null
+++ b/src/core/components/Profile/ProfileInfo.jsx
@@ -0,0 +1,49 @@
+"use client";
+
+import { useAuth } from "@/lib/contexts/auth";
+import { Avatar, Box, Chip, Divider, Stack, Typography } from "@mui/material";
+import moment from "jalali-moment";
+
+const ProfileInfo = () => {
+ const { user } = useAuth();
+
+ return (
+ <>
+
+
+
+
+ {`${user.full_name}`}
+
+
+ شماره تماس داخلی : {user.telephone_id}
+
+
+
+
+
+ آخرین ورود
+
+
+
+ {moment(user.last_login).locale("fa").fromNow()}
+
+
+
+
+
+
+
+ >
+ );
+};
+export default ProfileInfo;
diff --git a/src/core/components/Profile/index.jsx b/src/core/components/Profile/index.jsx
new file mode 100644
index 0000000..d538990
--- /dev/null
+++ b/src/core/components/Profile/index.jsx
@@ -0,0 +1,22 @@
+"use client";
+
+import { Stack } from "@mui/material";
+import ProfileInfo from "./ProfileInfo";
+import ProfileActions from "./ProfileActions";
+
+const Profile = () => {
+ return (
+
+
+
+
+ );
+};
+export default Profile;
diff --git a/src/core/components/StyledFab.jsx b/src/core/components/StyledFab.jsx
deleted file mode 100644
index 95c5ff7..0000000
--- a/src/core/components/StyledFab.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import {Fab, styled} from "@mui/material";
-
-const StyledFab = styled(Fab)`
- position: absolute;
- bottom: 16px;
- /* @noflip */
- left: 16px;
-`;
-
-export default StyledFab;
diff --git a/src/core/components/StyledForm.jsx b/src/core/components/StyledForm.jsx
index 253fc12..accf0ab 100644
--- a/src/core/components/StyledForm.jsx
+++ b/src/core/components/StyledForm.jsx
@@ -1,6 +1,5 @@
-import {Form} from "formik";
-import {styled} from "@mui/material/styles";
+import { styled } from "@mui/material";
-const StyledForm = styled(Form)``;
+const StyledForm = styled("form")``;
export default StyledForm;
diff --git a/src/core/components/StyledImage.jsx b/src/core/components/StyledImage.jsx
deleted file mode 100644
index 58dd65f..0000000
--- a/src/core/components/StyledImage.jsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import {styled} from "@mui/material";
-import Image from "next/image";
-
-const StyledImage = styled(Image)``;
-
-export default StyledImage;
diff --git a/src/core/components/TitlePage.jsx b/src/core/components/TitlePage.jsx
deleted file mode 100644
index 77c72ee..0000000
--- a/src/core/components/TitlePage.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import {useTranslations} from "next-intl";
-import Head from "next/head";
-
-const TitlePage = ({text}) => {
- const t = useTranslations();
- return (
-
-
- {text ? `${t("app_short_name")} | ${t(text)}` : t("app_short_name")}
-
-
- );
-};
-
-export default TitlePage;
diff --git a/src/core/components/Toasts/error.jsx b/src/core/components/Toasts/error.jsx
new file mode 100644
index 0000000..ffd6381
--- /dev/null
+++ b/src/core/components/Toasts/error.jsx
@@ -0,0 +1,222 @@
+import { toast } from "react-toastify";
+import { Box, Typography } from "@mui/material";
+import { Dangerous } from "@mui/icons-material";
+
+export const errorServerToast = (toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {"The request failed due to an internal error."}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: 5000,
+ hideProgressBar: true,
+ pauseOnHover: true,
+ closeOnClick: false,
+ draggable: true,
+ },
+ );
+
+export const errorUnauthorizedToast = (toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {"The user is not authorized to make the request."}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: 3000,
+ hideProgressBar: true,
+ pauseOnHover: true,
+ closeOnClick: false,
+ draggable: true,
+ },
+ );
+export const errorAccessDeniedToast = (message, toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {message || "Access Denied"}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: 3000,
+ hideProgressBar: true,
+ pauseOnHover: true,
+ closeOnClick: false,
+ draggable: true,
+ },
+ );
+
+export const errorLogicToast = (message, toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {message ||
+ "The request was well-formed but was unable to be followed due to semantic errors."}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: false,
+ closeOnClick: false,
+ draggable: false,
+ },
+ );
+
+export const errorValidationToast = (message, toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {message ||
+ "The request was well-formed but was unable to be followed due to semantic errors."}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: false,
+ closeOnClick: false,
+ draggable: false,
+ },
+ );
+
+export const errorTooManyToast = (toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {"Too many requests have been sent within a given time span."}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: false,
+ closeOnClick: false,
+ draggable: false,
+ },
+ );
+
+export const errorClientToast = (toastContainer) =>
+ toast.error(
+ () => (
+
+
+
+
+
+ {
+ "The API request is invalid or improperly formed. Consequently, the API server could not understand the request."
+ }
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: false,
+ closeOnClick: false,
+ draggable: false,
+ },
+ );
diff --git a/src/core/components/Toasts/success.jsx b/src/core/components/Toasts/success.jsx
new file mode 100644
index 0000000..7cdea7f
--- /dev/null
+++ b/src/core/components/Toasts/success.jsx
@@ -0,0 +1,35 @@
+import { toast } from "react-toastify";
+import { Box, Typography } from "@mui/material";
+import { Beenhere } from "@mui/icons-material";
+
+export const successToast = (toastContainer) =>
+ toast.success(
+ () => (
+
+
+
+
+
+ {"عملیات با موفقیت انجام شد"}
+
+
+
+
+ ),
+ {
+ icon: false,
+ containerId: toastContainer,
+ autoClose: 3000,
+ hideProgressBar: true,
+ pauseOnHover: true,
+ closeOnClick: false,
+ draggable: true,
+ },
+ );
diff --git a/src/core/components/UploadSystem.jsx b/src/core/components/UploadSystem.jsx
deleted file mode 100644
index b40fb46..0000000
--- a/src/core/components/UploadSystem.jsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import {Box, Button, Paper, Typography} from "@mui/material";
-import {useTranslations} from "next-intl";
-import AddIcon from "@mui/icons-material/Add";
-import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
-import {useRef} from "react";
-
-const UploadSystem = ({
- selectedImage,
- setselectedImage,
- handleUploadChange,
- fieldname,
- setFieldValue,
- imageAlt,
- imageSize,
- fileType,
- fileName,
- setShowAddIcon,
- showAddIcon,
- }) => {
- const t = useTranslations();
- const fileInputRef = useRef(null);
-
- const handleClick = () => {
- fileInputRef.current.click();
- };
-
- const handleDeleteImage = () => {
- setselectedImage(null);
- setFieldValue(fieldname, null);
- setShowAddIcon(true);
- if (fileInputRef.current) {
- fileInputRef.current.value = "";
- }
- };
-
- const isDocumentFormat = (fileType) => {
- const documentFormats = [
- "application/pdf",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- "application/vnd.ms-excel",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- ];
- return documentFormats.includes(fileType);
- };
-
- return (
-
- {showAddIcon ? (
- // Show the add icon and "Upload File" text when no image is selected
- <>
-
-
-
- {t("UploadSystem.upload_file")}
-
-
- >
- ) : (
- // Show the uploaded content along with the delete button when an image or document is selected
- <>
- {fileType && fileType.startsWith("image/") ? (
-
-
-
- ) : (
- fileType &&
- isDocumentFormat(fileType) && (
-
-
- {fileName}
-
-
- )
- )}
-
- >
- )}
-
-
- );
-};
-
-export default UploadSystem;
diff --git a/src/core/components/notifications/ErrorNotification.jsx b/src/core/components/notifications/ErrorNotification.jsx
deleted file mode 100644
index 776c904..0000000
--- a/src/core/components/notifications/ErrorNotification.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import DangerousIcon from "@mui/icons-material/Dangerous";
-import {Box, Typography} from "@mui/material";
-import {toast} from "react-toastify";
-
-const ErrorNotification = (pushToastList, notificationType, t, status, message) => {
- const toastId = toast(
- () => (
- <>
-
-
-
-
-
- {t("notifications.error")} ({t("notifications.code")}: {status})
-
-
- {message || t("notifications.error_static_text")}
-
-
-
-
- >
- ),
- {
- containerId: 'validation',
- autoClose: false,
- closeOnClick: false,
- draggable: false,
- }
- );
- pushToastList(notificationType, toastId);
-};
-
-export default ErrorNotification;
\ No newline at end of file
diff --git a/src/core/components/notifications/PendingNotification.jsx b/src/core/components/notifications/PendingNotification.jsx
deleted file mode 100644
index cc28a58..0000000
--- a/src/core/components/notifications/PendingNotification.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import {toast} from "react-toastify";
-
-const PendingNotification = (pushToastList, notificationType, t) => {
- const toastId = toast(t("notifications.pending"), {
- containerId: 'validation',
- autoClose: false,
- closeButton: false,
- closeOnClick: false,
- draggable: false,
- });
- pushToastList(notificationType, toastId);
-};
-
-export default PendingNotification;
\ No newline at end of file
diff --git a/src/core/components/notifications/SuccessNotification.jsx b/src/core/components/notifications/SuccessNotification.jsx
deleted file mode 100644
index 1207000..0000000
--- a/src/core/components/notifications/SuccessNotification.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import BeenhereIcon from "@mui/icons-material/Beenhere";
-import {Box, Typography} from "@mui/material";
-import {toast} from "react-toastify";
-
-const SuccessNotification = (pushToastList, notificationType, t, status) => {
- const toastId = toast(
- () => (
- <>
-
-
-
-
-
- {t("notifications.success")} ({t("notifications.code")}:{" "}
- {status})
-
-
- {t("notifications.success_static_text")}
-
-
-
-
- >
- ),
- {
- containerId: 'validation',
- autoClose: 3000,
- hideProgressBar: true,
- pauseOnHover: true,
- closeOnClick: false,
- draggable: true,
- }
- );
- pushToastList(notificationType, toastId);
-};
-
-export default SuccessNotification;
\ No newline at end of file
diff --git a/src/core/components/notifications/UploadFileNotification.jsx b/src/core/components/notifications/UploadFileNotification.jsx
deleted file mode 100644
index 1c20ba3..0000000
--- a/src/core/components/notifications/UploadFileNotification.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import DangerousIcon from "@mui/icons-material/Dangerous";
-import {Box, Typography} from "@mui/material";
-import {toast} from "react-toastify";
-
-const UploadFileNotification = (t) => {
- toast(
- ({closeToast}) => (
- <>
-
-
-
-
-
- {t("UploadSystem.uploadfile_error")}
-
-
-
-
- >
- ),
- {
- containerId: 'validation',
- toastId: 'upload',
- autoClose: 3000,
- hideProgressBar: true,
- pauseOnHover: true,
- closeOnClick: false,
- draggable: true,
- }
- );
-};
-
-export default UploadFileNotification;
\ No newline at end of file
diff --git a/src/core/components/notifications/WarningNotification.jsx b/src/core/components/notifications/WarningNotification.jsx
deleted file mode 100644
index bc2a1fb..0000000
--- a/src/core/components/notifications/WarningNotification.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import ReportIcon from "@mui/icons-material/Report";
-import {Box, Typography} from "@mui/material";
-import {toast} from "react-toastify";
-
-const WarningNotification = (pushToastList, notificationType, t, status) => {
- const toastId = toast(
- () => (
- <>
-
-
-
-
-
- {t("notifications.warning")} ({t("notifications.code")}:{" "}
- {status})
-
-
- {t("notifications.warning_static_text")}
-
-
-
-
- >
- ),
- {
- containerId: 'validation',
- autoClose: false,
- closeOnClick: false,
- draggable: false,
- }
- );
- pushToastList(notificationType, toastId);
-};
-
-export default WarningNotification;
\ No newline at end of file
diff --git a/src/core/components/notifications/index.jsx b/src/core/components/notifications/index.jsx
deleted file mode 100644
index 34e44f3..0000000
--- a/src/core/components/notifications/index.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import pendingNotification from "@/core/components/notifications/PendingNotification";
-import WarningNotification from "@/core/components/notifications/WarningNotification";
-import ErrorNotification from "@/core/components/notifications/ErrorNotification";
-import SuccessNotification from "@/core/components/notifications/SuccessNotification";
-
-const Notifications = (pushToastList, notificationType, t, status, message) => {
- switch (notificationType) {
- case "pending":
- pendingNotification(pushToastList, notificationType, t);
- break;
- case "warning":
- WarningNotification(pushToastList, notificationType, t, status);
- break;
- case "error":
- if (message) {
- ErrorNotification(pushToastList, notificationType, t, status, message)
- } else {
- ErrorNotification(pushToastList, notificationType, t, status)
- }
- break;
- case "success":
- SuccessNotification(pushToastList, notificationType, t, status);
- break;
- }
-};
-
-export default Notifications;
diff --git a/src/core/components/svgs/Svg403.jsx b/src/core/components/svgs/Svg403.jsx
deleted file mode 100644
index d706ed0..0000000
--- a/src/core/components/svgs/Svg403.jsx
+++ /dev/null
@@ -1,131 +0,0 @@
-import {useTheme} from "@mui/material/styles";
-
-const Svg403 = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
-
- return (
-
- )
-
-}
-
-export default Svg403
\ No newline at end of file
diff --git a/src/core/components/svgs/Svg404.jsx b/src/core/components/svgs/Svg404.jsx
deleted file mode 100644
index 159d7c6..0000000
--- a/src/core/components/svgs/Svg404.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import {useTheme} from "@mui/material/styles";
-
-const Svg404 = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
-
- return (
-
- )
-}
-
-export default Svg404
\ No newline at end of file
diff --git a/src/core/components/svgs/SvgChangePassword.jsx b/src/core/components/svgs/SvgChangePassword.jsx
deleted file mode 100644
index 1221d28..0000000
--- a/src/core/components/svgs/SvgChangePassword.jsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import {useTheme} from "@mui/material/styles";
-
-const SvgChangePassword = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
-
- return (
-
- )
-}
-
-export default SvgChangePassword
\ No newline at end of file
diff --git a/src/core/components/svgs/SvgDashboard.jsx b/src/core/components/svgs/SvgDashboard.jsx
deleted file mode 100644
index a636bf4..0000000
--- a/src/core/components/svgs/SvgDashboard.jsx
+++ /dev/null
@@ -1,117 +0,0 @@
-import {useTheme} from "@mui/material/styles";
-
-const SvgDashboard = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
-
- return (
-
- )
-}
-
-export default SvgDashboard
\ No newline at end of file
diff --git a/src/core/components/svgs/SvgError.jsx b/src/core/components/svgs/SvgError.jsx
new file mode 100644
index 0000000..756496e
--- /dev/null
+++ b/src/core/components/svgs/SvgError.jsx
@@ -0,0 +1,100 @@
+"use client";
+import { useTheme } from "@mui/material";
+
+const SvgError = ({ width, height, color = null }) => {
+ const theme = useTheme();
+ const fillColor = color || theme.palette.primary.main;
+
+ return (
+
+ );
+};
+
+export default SvgError;
diff --git a/src/core/components/svgs/SvgLoading.jsx b/src/core/components/svgs/SvgLoading.jsx
index 9ff61ff..661441e 100644
--- a/src/core/components/svgs/SvgLoading.jsx
+++ b/src/core/components/svgs/SvgLoading.jsx
@@ -1,136 +1,293 @@
-import {useTheme} from "@mui/material/styles";
+"use client";
+import { useTheme } from "@mui/material";
-const SvgLoading = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
+const SvgLoading = ({ width, height, color = null }) => {
+ const theme = useTheme();
+ const fillColor = color || theme.palette.primary.main;
- return (
-
- )
-}
+ return (
+
+ );
+};
-export default SvgLoading
\ No newline at end of file
+export default SvgLoading;
diff --git a/src/core/components/svgs/SvgLogin.jsx b/src/core/components/svgs/SvgLogin.jsx
deleted file mode 100644
index edf3b51..0000000
--- a/src/core/components/svgs/SvgLogin.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import {useTheme} from "@mui/material/styles";
-
-const SvgLogin = ({width, height}) => {
- const theme = useTheme()
- const fillColor = theme.palette.primary.main
-
- return (
-
- )
-
-}
-
-export default SvgLogin
\ No newline at end of file
diff --git a/src/core/components/svgs/SvgNotFound.jsx b/src/core/components/svgs/SvgNotFound.jsx
new file mode 100644
index 0000000..7c57e88
--- /dev/null
+++ b/src/core/components/svgs/SvgNotFound.jsx
@@ -0,0 +1,162 @@
+import { useTheme } from "@mui/material";
+
+const SvgNotFound = ({ width, height, color = null }) => {
+ const theme = useTheme();
+ const fillColor = color || theme.palette.primary.main;
+
+ return (
+
+ );
+};
+export default SvgNotFound;
diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js
deleted file mode 100644
index f949dac..0000000
--- a/src/core/data/apiRoutes.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
-
-//login
-export const GET_USER_TOKEN = BASE_URL + "/api/auth/login";
-//end login
-
-//edit profile
-export const UPDATE_AVATAR = BASE_URL + "";
-//end edit profile
-
-// role list
-export const GET_ROLE_LIST = BASE_URL + "/api/roles/list";
-// role list
-
-// province list
-export const GET_PROVINCE_LIST = BASE_URL + "/api/provinces";
-// province list
-
-// province list
-export const GET_CALLER_HISTORY = BASE_URL + "/api/calls/list";
-// province list
-
-//change password
-export const SET_USER_PASSWORD = BASE_URL + "/api/profile/change_password";
-//end change password
-
-//user data
-export const GET_USER = BASE_URL + "/api/profile/info";
-//user data
-
-//sidebar notification
-export const GET_SIDEBAR_NOTIFICATION = BASE_URL + "/dashboard/notification";
-//sidebar notification
-
-// role management
-export const GET_ROLES = BASE_URL + "/api/roles";
-export const ADD_ROLE = BASE_URL + "/api/roles";
-export const UPDATE_ROLE = BASE_URL + "/api/roles";
-export const DELETE_ROLE = BASE_URL + "/api/roles";
-
-export const GET_PERMISSIONS_LIST = BASE_URL + "/api/permissions/list";
-//role management
-
-//expert management
-export const GET_EXPERTS = BASE_URL + "/api/users";
-export const ADD_EXPERT = BASE_URL + "/api/users";
-export const UPDATE_EXPERT = BASE_URL + "/api/users";
-export const DELETE_EXPERT = BASE_URL + "/api/users";
-//expert management
-
-//call action history
-export const GET_CATEGORY = BASE_URL + "/api/categories";
-export const CALL_ACTION = BASE_URL + "/api/calls";
-//call action history
diff --git a/src/core/data/headerProfileItems.jsx b/src/core/data/headerProfileItems.jsx
deleted file mode 100644
index 577fba3..0000000
--- a/src/core/data/headerProfileItems.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import BorderColorIcon from "@mui/icons-material/BorderColor";
-import PasswordIcon from "@mui/icons-material/Password";
-
-const headerProfileItems = [
- {
- key: 0,
- name: "header.edit_profile",
- route: "/dashboard/edit-profile",
- icon: ,
- },
- {
- key: 1,
- name: "header.change_password",
- route: "/dashboard/change-password",
- icon: ,
- },
-];
-
-export default headerProfileItems;
diff --git a/src/core/data/sidebarMenu.jsx b/src/core/data/sidebarMenu.jsx
deleted file mode 100644
index 5c14462..0000000
--- a/src/core/data/sidebarMenu.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
-import AccessibilityIcon from '@mui/icons-material/Accessibility';
-import ManageAccountsIcon from '@mui/icons-material/ManageAccounts';
-
-const sidebarMenu = [
- [
- {
- key: "sidebar.dashboard",
- type: "page",
- route: "/dashboard",
- icon: ,
- selected: false,
- permission: "all",
- },
- {
- key: "sidebar.expert-management",
- type: "page",
- name: "expert_management",
- route: "/dashboard/expert-management",
- icon: ,
- selected: false,
- permission: "all",
- },
- {
- key: "sidebar.role-management",
- name : "role_management",
- type: "page",
- route: "/dashboard/role-management",
- icon: ,
- selected: false,
- permission: "manage_roles",
- },
- ],
-];
-
-export default sidebarMenu;
diff --git a/src/core/middlewares/withAuth.js b/src/core/middlewares/withAuth.js
new file mode 100644
index 0000000..c9286e7
--- /dev/null
+++ b/src/core/middlewares/withAuth.js
@@ -0,0 +1,44 @@
+"use client";
+import { useAuth } from "@/lib/contexts/auth";
+import { usePathname, useRouter } from "next/navigation";
+import { useEffect } from "react";
+import LoadingHardPage from "../components/LoadingHardPage";
+import { Stack, Typography } from "@mui/material";
+
+function WithAuthMiddleware({ children }) {
+ const router = useRouter();
+ const pathName = usePathname();
+ const { isAuth, initAuthState, errorState } = useAuth();
+
+ useEffect(() => {
+ if (!initAuthState) return;
+ if (!isAuth) {
+ router.replace(`/login?redirect=${encodeURIComponent(pathName)}`);
+ }
+ }, [isAuth, initAuthState]);
+
+ if (!initAuthState || !isAuth)
+ return (
+
+ {errorState.message}
+
+ {" "}
+ کد : {errorState.status}
+
+
+ ) : (
+ درحال احراز هویت...
+ )
+ }
+ loading={true}
+ />
+ );
+
+ return <>{children}>;
+}
+
+export default WithAuthMiddleware;
diff --git a/src/core/middlewares/withPermission.js b/src/core/middlewares/withPermission.js
new file mode 100644
index 0000000..f8b121a
--- /dev/null
+++ b/src/core/middlewares/withPermission.js
@@ -0,0 +1,47 @@
+"use client";
+
+import { Box, Typography } from "@mui/material";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+import { useEffect, useState } from "react";
+
+function WithPermission({ children, permission_name }) {
+ const { data, isLoading } = usePermissions();
+ const [cachedData, setCachedData] = useState(null);
+
+ useEffect(() => {
+ if (data) {
+ setCachedData(data);
+ }
+ }, [data]);
+
+ if (isLoading || !cachedData || !permission_name) {
+ return null;
+ }
+
+ const hasPermission =
+ permission_name.includes("all") ||
+ permission_name.some((permission) => cachedData.includes(permission));
+
+ if (!hasPermission) {
+ return (
+
+
+ شما دسترسی لازم به این صفحه را ندارید
+
+
+ );
+ }
+ return <>{children}>;
+}
+
+export default WithPermission;
diff --git a/src/core/middlewares/withWidget.js b/src/core/middlewares/withWidget.js
new file mode 100644
index 0000000..95180ab
--- /dev/null
+++ b/src/core/middlewares/withWidget.js
@@ -0,0 +1,5 @@
+const WithWidgetMiddleware = ({ children, enable }) => {
+ return enable ? <>{children}> : null;
+};
+
+export default WithWidgetMiddleware;
diff --git a/src/core/middlewares/withoutAuth.js b/src/core/middlewares/withoutAuth.js
new file mode 100644
index 0000000..396b848
--- /dev/null
+++ b/src/core/middlewares/withoutAuth.js
@@ -0,0 +1,45 @@
+"use client";
+import { useAuth } from "@/lib/contexts/auth";
+import { useRouter, useSearchParams } from "next/navigation";
+import { useEffect } from "react";
+import LoadingHardPage from "../components/LoadingHardPage";
+import { Stack, Typography } from "@mui/material";
+
+function WithoutAuthMiddleware({ children }) {
+ const router = useRouter();
+ const { isAuth, initAuthState, errorState } = useAuth();
+ const searchParams = useSearchParams();
+
+ const redirect = searchParams.get("redirect");
+
+ useEffect(() => {
+ if (!initAuthState) return;
+ if (isAuth) {
+ router.replace(redirect ? decodeURIComponent(redirect) : "/dashboard");
+ }
+ }, [isAuth, initAuthState]);
+
+ if (!initAuthState || isAuth)
+ return (
+
+ {errorState.message}
+
+ {" "}
+ کد : {errorState.status}
+
+
+ ) : (
+ درحال احراز هویت...
+ )
+ }
+ loading={true}
+ />
+ );
+ return <>{children}>;
+}
+
+export default WithoutAuthMiddleware;
diff --git a/src/core/utils/cacheRtl.js b/src/core/utils/cacheRtl.js
new file mode 100644
index 0000000..5830941
--- /dev/null
+++ b/src/core/utils/cacheRtl.js
@@ -0,0 +1,15 @@
+"use client";
+import createCache from "@emotion/cache";
+import { CacheProvider } from "@emotion/react";
+import { prefixer } from "stylis";
+import rtlPlugin from "stylis-plugin-rtl";
+
+// Create rtl cache
+export const rtlCache = createCache({
+ key: "mui-rtl",
+ stylisPlugins: [prefixer, rtlPlugin],
+});
+
+export function Rtl(props) {
+ return {props.children};
+}
diff --git a/src/core/utils/createEmotionCache.jsx b/src/core/utils/createEmotionCache.jsx
deleted file mode 100644
index 413fafe..0000000
--- a/src/core/utils/createEmotionCache.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import createCache from "@emotion/cache";
-import {prefixer} from "stylis";
-import stylisRTLPlugin from "stylis-plugin-rtl";
-
-const isBrowser = typeof document !== "undefined";
-
-export const createEmotionCacheLtr = () => {
- let insertionPoint;
-
- if (isBrowser) {
- const emotionInsertionPoint = document.querySelector(
- 'meta[name="emotion-insertion-point"]'
- );
- insertionPoint = emotionInsertionPoint ?? undefined;
- }
-
- return createCache({
- key: "mui-style",
- insertionPoint,
- });
-};
-
-export const createEmotionCacheRtl = () => {
- let insertionPoint;
-
- if (isBrowser) {
- const emotionInsertionPoint = document.querySelector(
- 'meta[name="emotion-insertion-point"]'
- );
- insertionPoint = emotionInsertionPoint ?? undefined;
- }
-
- return createCache({
- key: "muirtl",
- stylisPlugins: [prefixer, stylisRTLPlugin],
- insertionPoint,
- });
-};
diff --git a/src/core/utils/errorHandler.js b/src/core/utils/errorHandler.js
deleted file mode 100644
index e380e84..0000000
--- a/src/core/utils/errorHandler.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import Notifications from "@/core/components/notifications";
-
-export const errorSetting = (dismissToastList, t, notification) => {
- if (notification) {
- dismissToastList(["pending", "warning", "error", "success"])
- }
-}
-export const errorRequest = (dismissToastList, t, notification) => {
- if (notification) {
- dismissToastList(["pending", "warning", "error", "success"])
- }
-}
-
-export const errorResponse = (pushToastList, dismissToastList, response, clearToken, t, notification) => {
- if (notification) {
- dismissToastList(["pending", "warning", "error", "success"])
- }
- if (isServerError(response.status)) {
- errorServer(pushToastList, response, t, notification)
- } else if (isClientError(response.status)) {
- errorClient(pushToastList, response, clearToken, t, notification)
- }
-}
-
-const errorServer = (pushToastList, response, t, notification) => {
- if (notification) Notifications(pushToastList, "warning", t, response.status);
-}
-const errorClient = (pushToastList, response, clearToken, t, notification) => {
- switch (response.status) {
- case 401:
- clearToken()
- if (notification) Notifications(pushToastList, "error", t, response.status);
- break;
- case 422:
- if ('type' in response.data) {
- errorLogic(pushToastList, response, t, notification)
- break;
- }
- errorValidation(pushToastList, response, t, notification)
- break;
- case 429:
- if (notification) Notifications(pushToastList, "error", t, response.status);
- break
- default:
- if (notification) Notifications(pushToastList, "error", t, response.status);
- break
- }
-}
-
-const isServerError = status => status >= 500 && status <= 599;
-const isClientError = status => status >= 400 && status <= 499;
-
-const errorLogic = (pushToastList, response, t, notification) => {
- if (notification) Notifications(pushToastList, "error", t, response.status, response.data.message);
-}
-const errorValidation = (pushToastList, response, t, notification) => {
- if (notification) {
- const errorsMap = Object.keys(response.data.errors)
- const errorsArray = response.data.errors
-
- errorsMap.map((item, index) => {
- Notifications(pushToastList, "error", t, response.status, errorsArray[item][0]);
- })
- }
-}
\ No newline at end of file
diff --git a/src/core/utils/errorResponse.js b/src/core/utils/errorResponse.js
new file mode 100644
index 0000000..8d281ba
--- /dev/null
+++ b/src/core/utils/errorResponse.js
@@ -0,0 +1,72 @@
+"use client";
+import { toast } from "react-toastify";
+import {
+ errorAccessDeniedToast,
+ errorClientToast,
+ errorLogicToast,
+ errorServerToast,
+ errorTooManyToast,
+ errorUnauthorizedToast,
+ errorValidationToast,
+} from "@/core/components/Toasts/error";
+
+const isServerError = (status) => status >= 500 && status <= 599;
+const isClientError = (status) => status >= 400 && status <= 499;
+
+const errorServer = (response, notification, toastContainer) => {
+ if (notification) errorServerToast(toastContainer);
+};
+
+const errorClient = (response, notification, toastContainer, logout) => {
+ switch (response.status) {
+ case 401:
+ logout();
+ if (notification) errorUnauthorizedToast(toastContainer);
+ break;
+ case 403:
+ if (notification)
+ errorAccessDeniedToast(response.data.message, toastContainer);
+ break;
+ case 422:
+ if ("type" in response.data) {
+ if (Array.isArray(response.data.message)) {
+ response.data.message.map((item) => {
+ if (notification) errorLogicToast(item, toastContainer);
+ });
+ } else {
+ if (notification)
+ errorLogicToast(response.data.message, toastContainer);
+ }
+ break;
+ }
+ if (notification) {
+ const errorsMap = Object.keys(response.data.errors);
+ const errorsArray = response.data.errors;
+
+ errorsMap.map((item, index) => {
+ errorValidationToast(errorsArray[item][0], toastContainer);
+ });
+ }
+ break;
+ case 429:
+ if (notification) errorTooManyToast(toastContainer);
+ break;
+ default:
+ if (notification) errorClientToast(toastContainer);
+ break;
+ }
+};
+
+export const errorResponse = (
+ response,
+ notification,
+ toastContainer,
+ logout,
+) => {
+ if (notification) toast.dismiss({ containerId: toastContainer });
+ if (isServerError(response.status)) {
+ errorServer(response, notification, toastContainer);
+ } else if (isClientError(response.status)) {
+ errorClient(response, notification, toastContainer, logout);
+ }
+};
diff --git a/src/core/utils/filterMenuItems.js b/src/core/utils/filterMenuItems.js
new file mode 100644
index 0000000..ad10189
--- /dev/null
+++ b/src/core/utils/filterMenuItems.js
@@ -0,0 +1,19 @@
+export function filterMenuItems(items, _permissions = []) {
+ return items.reduce((acc, item) => {
+ if (item.permissions) {
+ if (
+ item.permissions.some((permission) => _permissions.includes(permission))
+ ) {
+ acc.push(item);
+ }
+ } else if (item.hasSubitems) {
+ const filteredSubItems = filterMenuItems(item.Subitems, _permissions);
+ if (filteredSubItems.length > 0) {
+ acc.push({ ...item, Subitems: filteredSubItems });
+ }
+ } else {
+ acc.push(item);
+ }
+ return acc;
+ }, []);
+}
diff --git a/src/core/utils/getValueByPath.js b/src/core/utils/getValueByPath.js
new file mode 100644
index 0000000..a03958a
--- /dev/null
+++ b/src/core/utils/getValueByPath.js
@@ -0,0 +1,14 @@
+export const getValueByPath = (obj, path) => {
+ const keys = path.split(".");
+
+ let value = obj;
+
+ for (const key of keys) {
+ if (value === undefined) {
+ return undefined;
+ }
+ value = value[key];
+ }
+
+ return value;
+};
diff --git a/src/core/utils/headerMenu.js b/src/core/utils/headerMenu.js
new file mode 100644
index 0000000..cd33e61
--- /dev/null
+++ b/src/core/utils/headerMenu.js
@@ -0,0 +1,15 @@
+const api = process.env.NEXT_PUBLIC_API_URL;
+
+export const headerMenu = [
+ // {
+ // title: "تصادفات",
+ // subMenu: [
+ // [
+ // {
+ // title: "تصادفات روزانه",
+ // href: api + "/v2/daily_accidents/create",
+ // },
+ // ],
+ // ],
+ // },
+];
diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js
new file mode 100644
index 0000000..9f08204
--- /dev/null
+++ b/src/core/utils/pageMenu.js
@@ -0,0 +1,12 @@
+import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
+
+export const pageMenu = [
+ {
+ id: "dashboard",
+ label: "پیشخوان",
+ type: "page",
+ route: "/dashboard",
+ icon: ,
+ permissions: ["all"],
+ },
+];
diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js
new file mode 100644
index 0000000..37e72fe
--- /dev/null
+++ b/src/core/utils/routes.js
@@ -0,0 +1,12 @@
+const api = process.env.NEXT_PUBLIC_API_URL;
+
+export const GET_USER_ROUTE = api + "/profile/info";
+export const GET_USER_LOGIN_ROUTE = api + "/auth/login";
+export const GET_USER_LOGOUT_ROUTE = api + "/auth/logout";
+export const GET_PERMISSIONS_ROUTE = "";
+export const GET_SIDEBAR_BADGE_ROUTE = "";
+
+export const GET_CATEGORY = api + "/categories";
+
+export const GET_CALLER_HISTORY = api + "/calls/list";
+export const CALL_ACTION = api + "/calls";
diff --git a/src/core/utils/succesHandler.js b/src/core/utils/succesHandler.js
deleted file mode 100644
index c852f86..0000000
--- a/src/core/utils/succesHandler.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import Notifications from "@/core/components/notifications";
-
-export const successRequest = (pushToastList, dismissToastList, response, t, options) => {
- if (options.notification && options.success.notification.show) {
- dismissToastList(["pending", "warning", "error", "success"])
- Notifications(pushToastList, "success", t, response.status);
- }
-}
\ No newline at end of file
diff --git a/src/core/utils/successRequest.js b/src/core/utils/successRequest.js
new file mode 100644
index 0000000..daa2ab7
--- /dev/null
+++ b/src/core/utils/successRequest.js
@@ -0,0 +1,10 @@
+"use client";
+import { toast } from "react-toastify";
+import { successToast } from "@/core/components/Toasts/success";
+
+export const successRequest = (notification, toastContainer) => {
+ if (notification) {
+ toast.dismiss({ containerId: toastContainer });
+ successToast(toastContainer);
+ }
+};
diff --git a/src/core/utils/theme-rtl.jsx b/src/core/utils/theme-rtl.jsx
deleted file mode 100644
index 33a9ae7..0000000
--- a/src/core/utils/theme-rtl.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import {createTheme} from "@mui/material/styles";
-import theme from "./theme";
-import {faIR} from "@mui/x-date-pickers/locales";
-
-const themeRtl = createTheme({
- direction: "rtl",
- typography: {
- fontFamily: `IRANSansFaNum, sans-serif`,
- },
- faIR,
- ...theme,
-});
-
-export default themeRtl;
diff --git a/src/core/utils/theme.js b/src/core/utils/theme.js
new file mode 100644
index 0000000..64f93f8
--- /dev/null
+++ b/src/core/utils/theme.js
@@ -0,0 +1,31 @@
+"use client";
+import { createTheme } from "@mui/material";
+
+const theme = createTheme({
+ direction: "rtl",
+ typography: {
+ fontFamily: `IRANSansFaNum, sans-serif`,
+ fontSize: 12,
+ },
+ palette: {
+ primary: {
+ main: "#0D47A1",
+ contrastText: "#fff",
+ },
+ secondary: {
+ main: "#90A4AE",
+ },
+ },
+ components: {
+ MuiBackdrop: {
+ styleOverrides: {
+ root: {
+ backdropFilter: "blur(2px)",
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ },
+ },
+});
+
+export default theme;
diff --git a/src/core/utils/theme.jsx b/src/core/utils/theme.jsx
deleted file mode 100644
index 672e8a8..0000000
--- a/src/core/utils/theme.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import {colord} from "colord";
-
-const theme = {
- palette: {
- primary: {
- main: process.env.NEXT_PUBLIC_PRIMARY_MAIN,
- contrastText: "#FFFFFF",
- light: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).lighten(0.1).toHex(),
- dark: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).darken(0.1).toHex(),
- },
- secondary: {
- main: process.env.NEXT_PUBLIC_SECONDARY_MAIN,
- contrastText: "#FFFFFF",
- light: colord(process.env.NEXT_PUBLIC_SECONDARY_MAIN).lighten(0.1).toHex(),
- dark: colord(process.env.NEXT_PUBLIC_SECONDARY_MAIN).darken(0.1).toHex(),
- },
- },
- components: {
- MuiBackdrop: {
- styleOverrides: {
- root: {
- backgroundColor: colord(process.env.NEXT_PUBLIC_PRIMARY_MAIN).darken(0.2).alpha(0.7).toHex(),
- },
- },
- },
- },
-};
-
-export default theme;
diff --git a/src/layouts/AppLayout.jsx b/src/layouts/AppLayout.jsx
deleted file mode 100644
index 61984f6..0000000
--- a/src/layouts/AppLayout.jsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import theme from "@/core/utils/theme";
-import useLanguage from "@/lib/app/hooks/useLanguage";
-import useLoading from "@/lib/app/hooks/useLoading";
-import useUser from "@/lib/app/hooks/useUser";
-import NextNProgress from "nextjs-progressbar";
-import {useEffect} from "react";
-import {ToastContainer} from "react-toastify";
-import useDirection from "@/lib/app/hooks/useDirection";
-import "react-toastify/dist/ReactToastify.css";
-import NetworkComponent from "@/core/components/NetworkComponent";
-import GlobalHead from "@/core/components/GlobalHead";
-
-function AppLayout({children, isBot}) {
- const {languageIsReady} = useLanguage();
- const {setLoadingPage} = useLoading();
- const {userChangedLanguage, token, isAuth} = useUser();
- const {directionApp} = useDirection();
-
- useEffect(() => {
- if (languageIsReady) {
- if (token) {
- if (isAuth) {
- if (userChangedLanguage) {
- setLoadingPage(true);
- return;
- }
- setLoadingPage(false);
- return;
- }
- setLoadingPage(true);
- return;
- }
- setLoadingPage(false);
- return;
- }
- setLoadingPage(true);
- }, [languageIsReady, token, isAuth, userChangedLanguage]);
-
- if (!isBot) {
- if (userChangedLanguage) return;
- if (!languageIsReady) return;
- }
-
- return (
- <>
-
-
-
-
-
- {children}
- >
- );
-}
-
-export default AppLayout;
diff --git a/src/layouts/CenterLayout.jsx b/src/layouts/CenterLayout.jsx
deleted file mode 100644
index 1e1b8bf..0000000
--- a/src/layouts/CenterLayout.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import {Fade, Stack} from "@mui/material";
-
-const CenterLayout = (props) => {
- return (
-
-
- {props.children}
-
-
- );
-};
-
-export default CenterLayout;
diff --git a/src/layouts/DashboardLayout.jsx b/src/layouts/DashboardLayout.jsx
deleted file mode 100644
index 72344d6..0000000
--- a/src/layouts/DashboardLayout.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import Dashboard from "src/components/layouts/Dashboard";
-import AppPermission from "@/middlewares/AppPermission";
-import CallWidget from "@/components/layouts/Dashboard/CallWidget";
-
-const DashboardLayout = (props) => {
- const permissions = ["NEXT_PUBLIC_HAS_WIDGET"];
- return (
- <>
-
-
-
-
- >
- );
-};
-
-export default DashboardLayout;
diff --git a/src/layouts/FullPageLayout.jsx b/src/layouts/FullPageLayout.jsx
deleted file mode 100644
index d6ed61e..0000000
--- a/src/layouts/FullPageLayout.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {Stack} from "@mui/material";
-
-const FullPageLayout = (props) => {
- return (
-
- {props.children}
-
- );
-};
-
-export default FullPageLayout;
diff --git a/src/layouts/MuiLayout.jsx b/src/layouts/MuiLayout.jsx
deleted file mode 100644
index eba3449..0000000
--- a/src/layouts/MuiLayout.jsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import NoSsrHandler from "@/core/components/NoSsrHandler";
-import {createEmotionCacheRtl} from "@/core/utils/createEmotionCache";
-import themeRtl from "@/core/utils/theme-rtl";
-import {CacheProvider} from "@emotion/react";
-import {GlobalStyles} from "@mui/material";
-import CssBaseline from "@mui/material/CssBaseline";
-import {ThemeProvider} from "@mui/material/styles";
-import Head from "next/head";
-
-const clientSideEmotionCacheRtl = createEmotionCacheRtl();
-
-const MuiLayout = ({children, isBot}) => {
- const emotionCache = clientSideEmotionCacheRtl;
- const theme = themeRtl;
-
- return (
-
-
-
-
-
-
-
-
-
- {children}
-
-
-
- );
-};
-
-export default MuiLayout;
diff --git a/src/layouts/ScrollableLayout.jsx b/src/layouts/ScrollableLayout.jsx
deleted file mode 100644
index 583edd7..0000000
--- a/src/layouts/ScrollableLayout.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {Box, Fade} from "@mui/material";
-
-const ScrollableLayout = (props) => {
- const overflowY = props?.y || "hidden";
- const overflowX = props?.x || "hidden";
-
- return (
-
-
- {props.children}
-
-
- );
-};
-
-export default ScrollableLayout;
diff --git a/src/lib/app/contexts/language.jsx b/src/lib/app/contexts/language.jsx
deleted file mode 100644
index e9e24f7..0000000
--- a/src/lib/app/contexts/language.jsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import {FA_DATATABLE_LOCALIZATION} from "&/locales/fa/datatable";
-import {useRouter} from "next/router";
-import {createContext, useEffect, useState} from "react";
-import useUser from "../hooks/useUser";
-
-export const LanguageContext = createContext();
-
-export const LanguageProvider = ({children}) => {
- const router = useRouter();
- const languageList = [
- {
- key: "fa",
- dir: "rtl",
- name: "فارسی",
- fontFamily: `IRANSans, sans-serif`,
- tableLocalization: FA_DATATABLE_LOCALIZATION,
- }
- ];
- const {user, userChangedLanguage, changeLanguageState} = useUser();
- const [languageIsReady, setLanguageIsReady] = useState(false);
- const [languageApp, setLanguageApp] = useState(process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE);
- const [directionApp, setDirectionApp] = useState(
- process.env.NEXT_PUBLIC_DEFAULT_DIRECTION
- );
-
- useEffect(() => {
- const lang = localStorage.getItem("_language");
-
- if (lang) {
- setLanguageApp(lang);
- }
- }, []);
-
- useEffect(() => {
- if (!languageApp) return;
-
- const lang = localStorage.getItem("_language");
-
- if (!lang) {
- localStorage.setItem("_language", languageApp);
- } else {
- if (languageApp != lang) {
- localStorage.setItem("_language", languageApp);
- }
- }
- }, [languageApp]);
-
- useEffect(() => {
- if (!router.isReady) return;
- if (user.user_language) {
- if (user.user_language != languageApp) {
- setLanguageApp(user.user_language);
- return;
- }
- }
-
- if (languageApp != router.locale) {
- router.replace(
- {pathname: router.pathname, query: router.query},
- router.asPath,
- {
- locale: languageApp,
- }
- );
- return;
- }
- for (const lang of languageList) {
- if (languageApp != lang.key) continue;
- setDirectionApp(lang.dir);
- document.dir = lang.dir;
- }
-
- const timer = setTimeout(() => {
- changeLanguageState(false);
- setLanguageIsReady(true);
- }, 1000);
-
- return () => {
- clearTimeout(timer);
- };
- }, [router.locale, router.isReady, userChangedLanguage, languageApp]);
-
- return (
-
- {children}
-
- );
-};
diff --git a/src/lib/app/contexts/loading.jsx b/src/lib/app/contexts/loading.jsx
deleted file mode 100644
index f5b8a47..0000000
--- a/src/lib/app/contexts/loading.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import LoadingHardPage from "@/core/components/LoadingHardPage";
-import {createContext, useState} from "react";
-
-export const LoadingContext = createContext();
-
-export const LoadingProvider = ({children}) => {
- const [loadingPage, setLoadingPage] = useState(false);
- return (
-
-
- {children}
-
- );
-};
diff --git a/src/lib/app/contexts/socket.jsx b/src/lib/app/contexts/socket.jsx
deleted file mode 100644
index a95bccf..0000000
--- a/src/lib/app/contexts/socket.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import {createContext, useEffect, useMemo, useRef, useState} from "react";
-import {io} from "socket.io-client";
-import useUser from "@/lib/app/hooks/useUser";
-import {useTranslations} from "next-intl";
-import {toast} from "react-toastify";
-import PowerIcon from "@mui/icons-material/Power";
-import PowerOffIcon from "@mui/icons-material/PowerOff";
-import useDirection from "@/lib/app/hooks/useDirection";
-
-export const SocketContext = createContext()
-
-export const SocketProvider = ({children}) => {
- const {user, isAuth} = useUser()
- const [connectionError, setConnectionError] = useState(false)
- const socketToastId = useRef(null);
- const t = useTranslations()
- const {directionApp} = useDirection();
- const socket = useMemo(() => io(process.env.NEXT_PUBLIC_SERVER_SOCKET_URL, {
- autoConnect: false,
- // transports: ['websocket'],
- auth: {
- token: ""
- }
- }), [])
-
- useEffect(() => {
- if (isAuth) {
- socket.auth.token = user.telephone_id
- return
- }
- socket.auth.token = ''
- }, [isAuth]);
-
- useEffect(() => {
- const connectErrorHandler = () => {
- setConnectionError(true)
- }
- const connectHandler = () => {
- setConnectionError(false)
- }
- socket.on("connect_error", connectErrorHandler);
- socket.on("connect", connectHandler);
-
- return () => {
- socket.off("connect_error", connectErrorHandler);
- socket.off("connect", connectHandler);
- }
- }, []);
-
- useEffect(() => {
- if (!connectionError) {
- toast.update(socketToastId.current, {
- type: toast.TYPE.SUCCESS,
- render: t('socket_is_connect_message'),
- autoClose: 2000,
- closeButton: true,
- closeOnClick: true,
- icon:
- });
- return
- }
- socketToastId.current = toast.warn(t('socket_is_not_connect_message'), {
- containerId: 'connection',
- draggable: false,
- autoClose: false, closeButton: false, closeOnClick: false, icon:
- })
-
- }, [connectionError]);
-
- return (
-
- {children}
-
- )
-}
\ No newline at end of file
diff --git a/src/lib/app/contexts/toast.jsx b/src/lib/app/contexts/toast.jsx
deleted file mode 100644
index b9d4cbc..0000000
--- a/src/lib/app/contexts/toast.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import {createContext, useReducer} from "react";
-import {toast} from "react-toastify";
-
-export const ToastContext = createContext()
-
-const reducer = (state, action) => {
- switch (action.type) {
- case "PUSH":
- return {
- ...state,
- [action.toast_type]: [...state[action.toast_type], action.toast_id]
- };
- case "DISMISS":
- action.toast_type.map((item) => {
- state[item].map((id) => {
- toast.dismiss(id);
- })
- state[item] = []
- });
- return state;
- }
-};
-
-export const ToastProvider = ({children}) => {
- const [state, dispatch] = useReducer(reducer, {
- pending: [],
- error: [],
- warning: [],
- success: []
- });
-
- return (
-
- {children}
-
- );
-};
diff --git a/src/lib/app/contexts/user.jsx b/src/lib/app/contexts/user.jsx
deleted file mode 100644
index da83e93..0000000
--- a/src/lib/app/contexts/user.jsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import {GET_USER} from "@/core/data/apiRoutes";
-import axios from "axios";
-import {createContext, useCallback, useEffect, useReducer} from "react";
-
-const initialUser = {
- isAuth: false,
- userChangedLanguage: false,
- token: null,
- user: {},
-};
-
-const reducer = (state, action) => {
- switch (action.type) {
- case "CLEAR_USER":
- return {...state, user: {}};
- case "CHANGE_USER":
- return {...state, user: action.user};
- case "CHANGE_USER_LANGUAGE":
- return {
- ...state,
- user: {...state.user, user_language: action.language},
- };
- case "CHANGE_AUTH_STATE":
- return {...state, isAuth: action.isAuth};
- case "CHANGE_LANGUAGE_STATE":
- return {...state, userChangedLanguage: action.userChangedLanguage};
- case "CLEAR_TOKEN":
- localStorage.removeItem("_token");
- return {...state, token: null};
- case "SET_TOKEN":
- localStorage.setItem("_token", action.token);
- return {...state, token: action.token};
- default:
- return state;
- }
-};
-
-export const UserContext = createContext();
-
-export const UserProvider = ({children}) => {
- const [state, dispatch] = useReducer(reducer, initialUser);
-
- const clearUser = useCallback(() => {
- dispatch({type: "CLEAR_USER"});
- }, []);
-
- const changeUser = useCallback((user) => {
- dispatch({type: "CHANGE_USER", user});
- }, []);
-
- const changeUserLanguage = useCallback(/* use in multi language app */);
-
- const changeAuthState = useCallback((isAuth) => {
- dispatch({type: "CHANGE_AUTH_STATE", isAuth});
- }, []);
-
- const changeLanguageState = useCallback((userChangedLanguage) => {
- dispatch({type: "CHANGE_LANGUAGE_STATE", userChangedLanguage});
- }, []);
-
- const clearToken = useCallback(() => {
- dispatch({type: "CLEAR_TOKEN"});
- }, []);
-
- const setToken = useCallback((token) => {
- dispatch({type: "SET_TOKEN", token});
- }, []);
-
- const getUser = useCallback(
- (callback = () => {
- }) => {
- axios
- .get(GET_USER, {
- headers: {authorization: `Bearer ${state.token}`},
- })
- .then(({data}) => {
- if (typeof callback === "function") callback(data.data);
- })
- .catch(error => {
- if (error.response.status === 401) clearToken()
- })
- },
- [state.token]
- );
-
- useEffect(() => {
- const localToken = localStorage.getItem("_token");
- if (localToken) dispatch({type: "SET_TOKEN", token: localToken});
- }, []);
-
- useEffect(() => {
- if (!state.token) {
- clearUser();
- changeAuthState(false);
- changeLanguageState(false);
- return;
- }
- getUser((data) => {
- changeUser(data);
- changeAuthState(true);
- changeLanguageState(true);
- });
- }, [state.token]);
-
- return (
-
- {children}
-
- );
-};
diff --git a/src/lib/app/hooks/useDirection.jsx b/src/lib/app/hooks/useDirection.jsx
deleted file mode 100644
index b2e01fe..0000000
--- a/src/lib/app/hooks/useDirection.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import {useContext} from "react";
-import {LanguageContext} from "../contexts/language";
-
-const useDirection = () => {
- const {directionApp} = useContext(LanguageContext);
-
- return {directionApp};
-};
-
-export default useDirection;
diff --git a/src/lib/app/hooks/useLanguage.jsx b/src/lib/app/hooks/useLanguage.jsx
deleted file mode 100644
index d663835..0000000
--- a/src/lib/app/hooks/useLanguage.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import {useContext} from "react";
-import {LanguageContext} from "../contexts/language";
-import useUser from "./useUser";
-
-const useLanguage = () => {
- const {isAuth, changeUserLanguage} = useUser();
- const {
- languageApp,
- setLanguageApp,
- languageIsReady,
- setLanguageIsReady,
- languageList,
- } = useContext(LanguageContext);
-
- const changeLanguage = (lang) => {
- if (lang == languageApp) return;
-
- setLanguageIsReady(false);
- setLanguageApp(lang);
- if (isAuth) {
- changeUserLanguage(lang);
- }
- };
-
- return {languageApp, changeLanguage, languageIsReady, languageList};
-};
-
-export default useLanguage;
diff --git a/src/lib/app/hooks/useLoading.jsx b/src/lib/app/hooks/useLoading.jsx
deleted file mode 100644
index a691bd7..0000000
--- a/src/lib/app/hooks/useLoading.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import {useContext} from "react";
-import {LoadingContext} from "../contexts/loading";
-
-const useLoading = () => {
- const {setLoadingPage} = useContext(LoadingContext);
-
- return {setLoadingPage};
-};
-
-export default useLoading;
diff --git a/src/lib/app/hooks/useNetwork.jsx b/src/lib/app/hooks/useNetwork.jsx
deleted file mode 100644
index 9c436a5..0000000
--- a/src/lib/app/hooks/useNetwork.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import {useEffect, useState} from "react";
-
-function useNetwork() {
- const [state, setState] = useState(() => {
- return {
- online: navigator.onLine,
- };
- });
- useEffect(() => {
- const handleOnline = () => {
- setState((prevState) => ({
- ...prevState,
- online: true,
- }));
- };
- const handleOffline = () => {
- setState((prevState) => ({
- ...prevState,
- online: false,
- }));
- };
-
- window.addEventListener("online", handleOnline);
- window.addEventListener("offline", handleOffline);
- return () => {
- window.removeEventListener("online", handleOnline);
- window.removeEventListener("offline", handleOffline);
- };
- }, []);
-
- return state;
-}
-
-export default useNetwork;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useNotification.jsx b/src/lib/app/hooks/useNotification.jsx
deleted file mode 100644
index 6e80bca..0000000
--- a/src/lib/app/hooks/useNotification.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import useSWR from 'swr'
-import {GET_SIDEBAR_NOTIFICATION} from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-const GLOBAL_HAS_VALUE = process.env.NEXT_PUBLIC_HAS_VALUE;
-const hasPermissionsValue = GLOBAL_HAS_VALUE ? JSON.parse(GLOBAL_HAS_VALUE) : [];
-const isNotificationEnabled = hasPermissionsValue.includes("NEXT_PUBLIC_HAS_NOTIFICATION");
-
-const useNotification = () => {
-
- const requestServer = useRequest({auth: true, notification: false})
-
- //swr config
- const fetcher = (...args) => {
- return requestServer(args, 'get').then((response) => {
- return response.data.data;
- }).catch(() => {
- })
- };
-
- const {data, mutate} = useSWR( isNotificationEnabled ? GET_SIDEBAR_NOTIFICATION : '', fetcher , {keepPreviousData:true})
- //swr config
-
- // render data
- return {notification_count: data, update_notification: mutate}
-}
-export default useNotification
\ No newline at end of file
diff --git a/src/lib/app/hooks/usePermissions.jsx b/src/lib/app/hooks/usePermissions.jsx
deleted file mode 100644
index 2e6fff5..0000000
--- a/src/lib/app/hooks/usePermissions.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import useRequest from "@/lib/app/hooks/useRequest";
-import useSWR from "swr";
-import {GET_PERMISSIONS_LIST} from "@/core/data/apiRoutes";
-
-const usePermissions = () => {
- const requestServer = useRequest({auth: true, notification: false})
- const fetcher = (...args) => {
- return requestServer(args, 'get').then((response) => {
- return response.data.data;
- }).catch(() => {
- })
- };
-
- const {data, isLoading} = useSWR(GET_PERMISSIONS_LIST, fetcher, {
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- keepPreviousData : true
- })
- const permissions_list = data
- //swr config
-
- // render data
- return {permissions_list, isLoading}
-}
-export default usePermissions;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useProvince.jsx b/src/lib/app/hooks/useProvince.jsx
deleted file mode 100644
index 2bc8c6b..0000000
--- a/src/lib/app/hooks/useProvince.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import {GET_PROVINCE_LIST} from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-import useSWR from "swr";
-
-const useProvince = () => {
- const requestServer = useRequest({auth: true, notification: false})
-
- //swr config
- const fetcher = (...args) => {
- return requestServer(args, 'get').then(({data}) => {
- return data.data;
- }).catch(() => {
- })
- };
-
- const {data, isLoading} = useSWR(GET_PROVINCE_LIST, fetcher, {
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- keepPreviousData: true
- });
-
- return {
- provinceList: data,
- isLoadingProvinceList: isLoading,
- errorProvinceList: !data
- }
-};
-
-export default useProvince;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useRequest.jsx b/src/lib/app/hooks/useRequest.jsx
deleted file mode 100644
index 4c3be1d..0000000
--- a/src/lib/app/hooks/useRequest.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import axios from "axios";
-import {successRequest} from "@/core/utils/succesHandler";
-import {useTranslations} from "next-intl";
-import useUser from "@/lib/app/hooks/useUser";
-import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler";
-import useNetwork from "@/lib/app/hooks/useNetwork";
-import Notifications from "@/core/components/notifications";
-import useToast from "@/lib/app/hooks/useToast";
-
-const defaultOptions = {
- auth: false, data: {}, requestOptions: {
- headers: {}
- }, notification: true, pending: true, success: {
- notification: {
- show: true,
- },
- }, failed: {
- notification: {
- show: true,
- },
- },
-}
-const useRequest = (initOptions) => {
- const network = useNetwork()
- const t = useTranslations()
- const {token, clearToken} = useUser()
- const {pushToastList, dismissToastList} = useToast();
- let _options = {...defaultOptions, ...initOptions}
-
- function requestServer(url = '', method = 'get', options) {
- _options = {..._options, ...options}
- if (_options.auth) _options = {
- ..._options, requestOptions: {
- ..._options.requestOptions,
- headers: {..._options.requestOptions.headers, authorization: `Bearer ${token}`}
- }
- }
- return new Promise((resolve, reject) => {
- if (!network.online) {
- reject()
- return
- }
- if (_options.notification && _options.failed.notification.show && _options.pending) {
- dismissToastList(["pending", "warning", "error", "success"]);
- Notifications(pushToastList, "pending", t);
- }
-
- axios({
- url: url, method: method, data: _options.data, ..._options.requestOptions
- })
- .then(response => {
- successRequest(pushToastList, dismissToastList, response, t, _options)
- resolve(response)
- })
- .catch(error => {
- if (error.response) {
- errorResponse(pushToastList, dismissToastList, error.response, clearToken, t, _options.notification && _options.failed.notification.show)
- } else if (error.request) {
- errorRequest(dismissToastList, t, _options.notification && _options.failed.notification.show)
- } else {
- errorSetting(dismissToastList, t, _options.notification && _options.failed.notification.show)
- }
- reject(error)
- })
- });
- }
-
- return requestServer
-}
-
-export default useRequest
\ No newline at end of file
diff --git a/src/lib/app/hooks/useRole.jsx b/src/lib/app/hooks/useRole.jsx
deleted file mode 100644
index b4c231c..0000000
--- a/src/lib/app/hooks/useRole.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import {GET_ROLE_LIST} from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-import useSWR from "swr";
-
-const useRole = () => {
- const requestServer = useRequest({auth: true, notification: false})
-
- //swr config
- const fetcher = (...args) => {
- return requestServer(args, 'get').then(({data}) => {
- return data.data;
- }).catch(() => {
- })
- };
-
- const {data, isLoading} = useSWR(GET_ROLE_LIST, fetcher, {
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- keepPreviousData: true
- });
-
- return {
- roleList: data,
- isLoadingRoleList: isLoading,
- errorRoleList: !data
- }
-};
-
-export default useRole;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useSocket.jsx b/src/lib/app/hooks/useSocket.jsx
deleted file mode 100644
index 3b9855d..0000000
--- a/src/lib/app/hooks/useSocket.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import {useContext} from "react";
-import {SocketContext} from "@/lib/app/contexts/socket";
-
-const useSocket = () => {
- const {socket} = useContext(SocketContext)
-
- return socket
-}
-
-export default useSocket
\ No newline at end of file
diff --git a/src/lib/app/hooks/useToast.jsx b/src/lib/app/hooks/useToast.jsx
deleted file mode 100644
index 5e1d5b4..0000000
--- a/src/lib/app/hooks/useToast.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {useContext} from "react";
-import {ToastContext} from "@/lib/app/contexts/toast";
-
-const useToast = () => {
- const {dispatch} = useContext(ToastContext);
-
- const pushToastList = (toast_type, toast_id) => {
- dispatch({type: "PUSH", toast_type, toast_id});
- };
-
- const dismissToastList = (toast_type) => {
- dispatch({type: "DISMISS", toast_type});
- };
-
- return {
- pushToastList,
- dismissToastList
- }
-};
-
-export default useToast;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useUser.jsx b/src/lib/app/hooks/useUser.jsx
deleted file mode 100644
index b0bbc1a..0000000
--- a/src/lib/app/hooks/useUser.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import {useContext} from "react";
-import {UserContext} from "../contexts/user";
-
-const useUser = () => {
- const {
- isAuth,
- userChangedLanguage,
- token,
- user,
- getUser,
- clearUser,
- changeUser,
- changeAuthState,
- changeLanguageState,
- clearToken,
- setToken,
- } = useContext(UserContext);
-
- return {
- isAuth,
- userChangedLanguage,
- token,
- user,
- getUser,
- clearUser,
- changeUser,
- changeAuthState,
- changeLanguageState,
- clearToken,
- setToken,
- };
-};
-
-export default useUser;
diff --git a/src/lib/callWidget/contexts/answers.jsx b/src/lib/callWidget/contexts/answers.jsx
deleted file mode 100644
index 96a150c..0000000
--- a/src/lib/callWidget/contexts/answers.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { createContext, useEffect, useReducer, useState } from "react";
-import { GET_CATEGORY } from "@/core/data/apiRoutes";
-import useRequest from "@/lib/app/hooks/useRequest";
-
-const reducer = (state, action) => {
- switch (action.type) {
- case "CHANGE_ACTIVE_TAB":
- return state.map((answer, index) =>
- action.newValue === index
- ? { ...answer, active: true }
- : {
- ...answer,
- active: false,
- }
- );
- case "CHANGE_LIST":
- return [...action.newList];
- case "CHANGE_ACTIVE_ID":
- return state.map((answer, index) =>
- action.tab_id === answer.id
- ? {
- ...answer,
- active_category_id: action.category_id,
- }
- : { ...answer }
- );
- default:
- return state;
- }
-};
-
-const submission = (handleCategories, operation) => {
- switch (operation.type) {
- case "SET_CATEGORIES":
- return { ...handleCategories, categoryLists: operation.categoriesByAPI };
- case "SET_SUBCATEGORIES":
- return { ...handleCategories, subCategoryLists: operation.subCategoriesByAPI };
- default:
- return handleCategories;
- }
-};
-
-export const AnswersContext = createContext();
-export const AnswersProvider = ({ children }) => {
- const requestServer = useRequest({ auth: true, notification: false });
- const [openCallDialog, setOpenCallDialog] = useState(false);
- const [activeTab, setActiveTab] = useState(0);
- const [handleCategories, operation] = useReducer(submission, {
- categoryLists: [],
- subCategoryLists: [],
- });
- const [state, dispatch] = useReducer(reducer, []);
-
- useEffect(() => {
- requestServer(GET_CATEGORY, "get")
- .then(({ data }) => {
- const subCategoriesByAPI = data.data;
- const categoriesByAPI = subCategoriesByAPI.reduce((accumulator, currentValue) => {
- if (!accumulator.find((item) => item.category_id === currentValue.category_id)) {
- accumulator.push(currentValue);
- }
- return accumulator;
- }, []);
- operation({ type: "SET_CATEGORIES", categoriesByAPI });
- operation({ type: "SET_SUBCATEGORIES", subCategoriesByAPI });
- })
- .catch(() => {});
- }, []);
-
- return (
-
- {children}
-
- );
-};
diff --git a/src/lib/callWidget/contexts/categories.jsx b/src/lib/callWidget/contexts/categories.jsx
deleted file mode 100644
index 533dfc3..0000000
--- a/src/lib/callWidget/contexts/categories.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { createContext, useCallback, useEffect, useReducer } from "react";
-import useRequest from "@/lib/app/hooks/useRequest";
-import { GET_CATEGORY } from "@/core/data/apiRoutes";
-
-const reducer = (state, action) => {
- switch (action.type) {
- case "CHANGE_ACTIVE_ID":
- return { ...state, active_id: action.id };
- case "SET_CATEGORIES":
- return { ...state, categoryLists: action.cat };
- case "SET_SUBCATEGORIES":
- return { ...state, subCategoryLists: action.subCat };
- default:
- return state;
- }
-};
-export const CategoriesContext = createContext();
-
-export const CategoriesProvider = ({ children }) => {
- const requestServer = useRequest({ auth: true, notification: false });
- const [state, dispatch] = useReducer(reducer, {
- categoryLists: [],
- subCategoryLists: [],
- active_id: null,
- });
-
- useEffect(() => {
- requestServer(GET_CATEGORY, "get")
- .then(({ data }) => {
- const subCat = data.data;
- const cat = subCat.reduce((accumulator, currentValue) => {
- if (!accumulator.find((item) => item.category_id === currentValue.category_id)) {
- accumulator.push(currentValue);
- }
- return accumulator;
- }, []);
- dispatch({ type: "SET_CATEGORIES", cat });
- dispatch({ type: "SET_SUBCATEGORIES", subCat });
- })
- .catch(() => {});
- }, []);
-
- const setCategoryID = useCallback((id) => {
- dispatch({ type: "CHANGE_ACTIVE_ID", id });
- });
-
- return (
-
- {children}
-
- );
-};
diff --git a/src/lib/callWidget/hooks/useAnswers.jsx b/src/lib/callWidget/hooks/useAnswers.jsx
deleted file mode 100644
index 149b1d3..0000000
--- a/src/lib/callWidget/hooks/useAnswers.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { useContext } from "react";
-import { AnswersContext } from "@/lib/callWidget/contexts/answers";
-
-const useAnswers = () => {
- const { state, dispatch, activeTab, setActiveTab } = useContext(AnswersContext);
-
- const changeActiveTabAnswers = (newValue) => {
- dispatch({ type: "CHANGE_ACTIVE_TAB", newValue });
- setActiveTab(newValue);
- };
- const newAnswerTab = (data) => {
- const newAnswer = {
- id: data.id,
- phone_number: data.phone_number,
- date: new Date(),
- active: true,
- active_category_id: null,
- };
- const newList = [...state, newAnswer];
- dispatch({ type: "CHANGE_LIST", newList });
- changeActiveTabAnswers(newList.length - 1);
- };
-
- const closeAnswerTab = (id) => {
- const index = state.findIndex((answer) => answer.id === id);
- const newIndex = index === 0 ? 0 : index - 1;
- const newList = [...state];
- newList.splice(index, 1);
- if (newList.length !== 0) {
- newList[newIndex].active = true;
- setActiveTab(newIndex);
- }
- dispatch({ type: "CHANGE_LIST", newList });
- };
-
- return {
- answersList: state,
- activeTab,
- setActiveTab,
- changeActiveTabAnswers,
- closeAnswerTab,
- newAnswerTab,
- };
-};
-
-export default useAnswers;
diff --git a/src/lib/callWidget/hooks/useCallDialog.jsx b/src/lib/callWidget/hooks/useCallDialog.jsx
deleted file mode 100644
index 30dd599..0000000
--- a/src/lib/callWidget/hooks/useCallDialog.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import {useContext} from "react";
-import {AnswersContext} from "@/lib/callWidget/contexts/answers";
-
-const useCallDialog = () => {
- const {openCallDialog, setOpenCallDialog} = useContext(AnswersContext)
-
- return {openCallDialog, setOpenCallDialog}
-}
-
-export default useCallDialog
\ No newline at end of file
diff --git a/src/lib/callWidget/hooks/useCallerHistory.jsx b/src/lib/callWidget/hooks/useCallerHistory.jsx
deleted file mode 100644
index 810209d..0000000
--- a/src/lib/callWidget/hooks/useCallerHistory.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import useRequest from "@/lib/app/hooks/useRequest";
-import {useEffect, useState} from "react";
-import useSWR from "swr";
-import {GET_CALLER_HISTORY} from "@/core/data/apiRoutes";
-
-const useCallerHistory = (call_id, phone_number, max_size) => {
- const requestServer = useRequest({auth: true, notification: false});
- const [validData, setValidData] = useState([]);
-
- //swr config
- const fetcher = (...args) => {
- return requestServer(args, 'get').then(({data}) => {
- return data.data;
- }).catch(() => {
- })
- };
-
- const {data, isLoading} = useSWR(`${GET_CALLER_HISTORY}?phone_number=${phone_number}&size=${max_size}`, fetcher, {
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- keepPreviousData: true
- });
-
- useEffect(() => {
- data && setValidData(data.filter((item) => item.id != call_id));
- }, [data, call_id]);
-
- return {
- firstItemOfHistory: validData.length === 0 ? false : validData[0],
- historyList: validData.length < 2 ? false : validData.slice(1),
- isLoadingHistoryList: isLoading,
- errorHistoryList: !data
- }
-};
-
-export default useCallerHistory;
\ No newline at end of file
diff --git a/src/lib/callWidget/hooks/useCategories.jsx b/src/lib/callWidget/hooks/useCategories.jsx
deleted file mode 100644
index 423bd67..0000000
--- a/src/lib/callWidget/hooks/useCategories.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { useContext } from "react";
-import { AnswersContext } from "@/lib/callWidget/contexts/answers";
-
-const useCategories = () => {
- const { categoryLists, subCategoryLists, active_category_id, dispatch } = useContext(AnswersContext);
-
- const setActiveCategoryID = (tab_id, category_id) => {
- dispatch({ type: "CHANGE_ACTIVE_ID", tab_id, category_id });
- };
- return {
- categoryLists,
- subCategoryLists,
- active_category_id,
- setActiveCategoryID,
- };
-};
-export default useCategories;
diff --git a/src/lib/contexts/auth.js b/src/lib/contexts/auth.js
new file mode 100644
index 0000000..e56dd22
--- /dev/null
+++ b/src/lib/contexts/auth.js
@@ -0,0 +1,109 @@
+"use client";
+import { GET_USER_ROUTE } from "@/core/utils/routes";
+import axios from "axios";
+import {
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useReducer,
+ useState,
+} from "react";
+
+const initAuth = {
+ initAuthState: false,
+ isAuth: false,
+ user: {},
+};
+
+const authReducer = (state, action) => {
+ switch (action.type) {
+ case "CLEAR_USER":
+ return { ...state, user: {} };
+ case "CHANGE_USER":
+ return { ...state, user: action.user };
+ case "CHANGE_AUTH_STATE":
+ return { ...state, isAuth: action.isAuth };
+ case "CHANGE_INIT_AUTH":
+ return { ...state, initAuthState: action.initAuthState };
+ default:
+ return state;
+ }
+};
+
+const AuthContext = createContext();
+
+export const AuthProvider = ({ children }) => {
+ const [errorState, setErrorState] = useState({ status: null, message: "" });
+ const [state, dispatch] = useReducer(authReducer, initAuth);
+
+ const clearUser = useCallback(() => {
+ dispatch({ type: "CLEAR_USER" });
+ }, []);
+
+ const changeUser = useCallback((user) => {
+ dispatch({ type: "CHANGE_USER", user });
+ }, []);
+
+ const changeAuthState = useCallback((isAuth) => {
+ dispatch({ type: "CHANGE_AUTH_STATE", isAuth });
+ }, []);
+
+ const changeInitAuth = useCallback((initAuthState) => {
+ dispatch({ type: "CHANGE_INIT_AUTH", initAuthState });
+ }, []);
+
+ const logout = () => {
+ clearUser();
+ changeAuthState(false);
+ changeInitAuth(true);
+ };
+
+ const getUser = useCallback(async () => {
+ try {
+ const { data } = await axios.get(GET_USER_ROUTE, {
+ withCredentials: true,
+ });
+ changeUser(data.data);
+ changeAuthState(true);
+ changeInitAuth(true);
+ setErrorState(false);
+ } catch (error) {
+ if (error.response && error.response.status === 401) {
+ clearUser();
+ changeAuthState(false);
+ changeInitAuth(true);
+ return;
+ }
+ let status =
+ error.response && error.response.status
+ ? error.response.status
+ : "نامشخص";
+ setErrorState({
+ status,
+ message: " مشکلی در احراز هویت رخ داده است . دقایقی بعد امتحان کنید!!!",
+ });
+ }
+ }, [clearUser, changeUser, changeAuthState, changeInitAuth]);
+
+ useEffect(() => {
+ getUser();
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useAuth = () => useContext(AuthContext);
diff --git a/src/lib/contexts/call.js b/src/lib/contexts/call.js
new file mode 100644
index 0000000..df634b2
--- /dev/null
+++ b/src/lib/contexts/call.js
@@ -0,0 +1,106 @@
+"use client";
+import {
+ createContext,
+ useReducer,
+ useState,
+ useCallback,
+ useMemo,
+ useContext,
+} from "react";
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "CHANGE_ACTIVE_TAB":
+ return state.map((call, index) => ({
+ ...call,
+ active: index === action.index_call,
+ }));
+ case "CHANGE_LIST":
+ return [...action.new_list];
+ case "CHANGE_ACTIVE_CATEGORY_ID":
+ return state.map((call) =>
+ call.id === action.tab_id
+ ? { ...call, active_category_id: action.category_id }
+ : call,
+ );
+ default:
+ return state;
+ }
+};
+
+export const CallContext = createContext(null);
+
+export const CallProvider = ({ children }) => {
+ const [openCallDialog, setOpenCallDialog] = useState(false);
+ const [activeCall, setActiveCall] = useState(0);
+ const [calls, dispatch] = useReducer(reducer, []);
+
+ const changeActiveTab = useCallback((index_call) => {
+ dispatch({ type: "CHANGE_ACTIVE_TAB", index_call });
+ }, []);
+
+ const changeList = useCallback((new_list) => {
+ dispatch({ type: "CHANGE_LIST", new_list });
+ }, []);
+
+ const changeActiveCategoryId = useCallback((tab_id, category_id) => {
+ dispatch({ type: "CHANGE_ACTIVE_CATEGORY_ID", tab_id, category_id });
+ }, []);
+
+ const changeActiveTabCall = (newValue) => {
+ changeActiveTab(newValue);
+ setActiveCall(newValue);
+ };
+
+ const newCall = useCallback(
+ (data) => {
+ const newCall = {
+ id: data.id,
+ phone_number: data.phone_number,
+ date: new Date(),
+ active: true,
+ active_category_id: null,
+ };
+ const newList = [...calls, newCall];
+ changeList(newList);
+ changeActiveTabCall(newList.length - 1);
+ },
+ [calls],
+ );
+
+ const closeCall = useCallback(
+ (id) => {
+ const index = calls.findIndex((answer) => answer.id === id);
+ const newIndex = index === 0 ? 0 : index - 1;
+ const newList = [...calls];
+ newList.splice(index, 1);
+ if (newList.length !== 0) {
+ newList[newIndex].active = true;
+ changeActiveTabCall(newIndex);
+ }
+ changeList(newList);
+ },
+ [calls],
+ );
+
+ const contextValue = useMemo(
+ () => ({
+ openCallDialog,
+ setOpenCallDialog,
+ calls,
+ newCall,
+ closeCall,
+ activeCall,
+ setActiveCall,
+ changeActiveCategoryId,
+ changeActiveTabCall,
+ }),
+ [openCallDialog, calls, activeCall],
+ );
+
+ return (
+ {children}
+ );
+};
+
+export const useCall = () => useContext(CallContext);
diff --git a/src/lib/contexts/category.js b/src/lib/contexts/category.js
new file mode 100644
index 0000000..79e8360
--- /dev/null
+++ b/src/lib/contexts/category.js
@@ -0,0 +1,72 @@
+import { GET_CATEGORY } from "@/core/utils/routes";
+import {
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useReducer,
+} from "react";
+import useRequest from "../hooks/useRequest";
+
+const initialState = {
+ categoryLists: [],
+ subCategoryLists: [],
+ active_category_id: null,
+};
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "SET_CATEGORIES":
+ return { ...state, categoryLists: action.payload };
+ case "SET_SUBCATEGORIES":
+ return { ...state, subCategoryLists: action.payload };
+ default:
+ return state;
+ }
+};
+
+export const CategoriesContext = createContext(null);
+
+export const CategoriesProvider = ({ children }) => {
+ const requestServer = useRequest({ notificationShow: false });
+
+ const [state, dispatch] = useReducer(reducer, initialState);
+
+ useEffect(() => {
+ const fetchCategories = async () => {
+ try {
+ const { data } = await requestServer(GET_CATEGORY, "get");
+ const subCategories = data.data;
+
+ const categories = Array.from(
+ new Map(
+ subCategories.map((item) => [item.category_id, item]),
+ ).values(),
+ );
+
+ dispatch({ type: "SET_CATEGORIES", payload: categories });
+ dispatch({ type: "SET_SUBCATEGORIES", payload: subCategories });
+ } catch (error) {}
+ };
+
+ fetchCategories();
+ }, []);
+
+ const contextValue = useMemo(
+ () => ({
+ categoryLists: state.categoryLists,
+ subCategoryLists: state.subCategoryLists,
+ active_category_id: state.active_category_id,
+ }),
+ [state],
+ );
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useCategory = () => useContext(CategoriesContext);
diff --git a/src/lib/contexts/socket.js b/src/lib/contexts/socket.js
new file mode 100644
index 0000000..15a4e31
--- /dev/null
+++ b/src/lib/contexts/socket.js
@@ -0,0 +1,104 @@
+"use client";
+import { Power, PowerOff } from "@mui/icons-material";
+import {
+ createContext,
+ useContext,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+ useCallback,
+} from "react";
+import { toast } from "react-toastify";
+import { io } from "socket.io-client";
+import { useAuth } from "./auth";
+
+const SocketContext = createContext({
+ socket: null,
+ status: "",
+});
+
+export const useSocket = () => useContext(SocketContext);
+
+export const SocketProvider = ({ children }) => {
+ const { user } = useAuth();
+ const socketToastId = useRef(null);
+ const [status, setStatus] = useState("");
+
+ const socket = useMemo(() => {
+ return io(`${process.env.NEXT_PUBLIC_SERVER_SOCKET_URL}`, {
+ path: "/notification/socket.io",
+ autoConnect: false,
+ auth: { token: null },
+ });
+ }, []);
+
+ useEffect(() => {
+ if (user?.telephone_id) {
+ socket.auth.token = user.telephone_id;
+ }
+ }, [user, socket]);
+
+ const handleConnect = useCallback(() => setStatus("connected"), []);
+ const handleDisconnect = useCallback(() => setStatus("disconnected"), []);
+ const handleConnectError = useCallback(() => setStatus("error"), []);
+
+ useEffect(() => {
+ socket.on("connect", handleConnect);
+ socket.on("disconnect", handleDisconnect);
+ socket.on("connect_error", handleConnectError);
+
+ return () => {
+ socket.off("connect", handleConnect);
+ socket.off("disconnect", handleDisconnect);
+ socket.off("connect_error", handleConnectError);
+ };
+ }, [socket, handleConnect, handleDisconnect, handleConnectError]);
+
+ useEffect(() => {
+ if (status === "connected") {
+ toast.update(socketToastId.current, {
+ containerId: "socket_connection",
+ type: "success",
+ render: "ارتباط با سرور برقرار شد",
+ autoClose: 2000,
+ closeButton: true,
+ closeOnClick: true,
+ icon: ({ theme, type }) => ,
+ });
+ } else if (status === "error" || status === "disconnected") {
+ if (socketToastId.current) {
+ toast.update(socketToastId.current, {
+ containerId: "socket_connection",
+ type: "warning",
+ render: "ارتباط با سرور قطع شد. در حال تلاش برای بازیابی…",
+ autoClose: false,
+ closeButton: false,
+ draggable: false,
+ icon: ({ theme, type }) => ,
+ });
+ } else {
+ socketToastId.current = toast.warn(
+ "ارتباط با سرور قطع شد. در حال تلاش برای بازیابی…",
+ {
+ containerId: "socket_connection",
+ autoClose: false,
+ closeButton: false,
+ draggable: false,
+ icon: ({ theme, type }) => ,
+ },
+ );
+ }
+ }
+ }, [status]);
+
+ const contextValue = useMemo(() => ({ socket, status }), [socket, status]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default SocketContext;
diff --git a/src/lib/contexts/tableSetting.js b/src/lib/contexts/tableSetting.js
new file mode 100644
index 0000000..6009f88
--- /dev/null
+++ b/src/lib/contexts/tableSetting.js
@@ -0,0 +1,189 @@
+"use client";
+
+import { createContext, useCallback, useEffect, useState } from "react";
+import LZString from "lz-string";
+
+export const TableSettingContext = createContext();
+
+const decompressData = (compressedData) => {
+ try {
+ const decompressed = LZString.decompressFromUTF16(compressedData);
+ if (decompressed === null) {
+ localStorage.removeItem("_setting-app");
+ return null;
+ } else {
+ return JSON.parse(decompressed);
+ }
+ } catch (error) {
+ localStorage.removeItem("_setting-app");
+ return null;
+ }
+};
+
+export const TableSettingProvider = ({ children }) => {
+ const [settingStore, setSettingStore] = useState({});
+
+ useEffect(() => {
+ const compressedData = localStorage.getItem("_setting-app");
+
+ const data = compressedData ? decompressData(compressedData) : null;
+ if (data) {
+ setSettingStore(data);
+ }
+ }, []);
+
+ const hideAction = useCallback(
+ (user_id, page_name, table_name, settingValue) => {
+ clearAction(user_id, page_name, table_name, "hides");
+ updateSettingStorage(
+ user_id,
+ page_name,
+ table_name,
+ "hides",
+ settingValue,
+ );
+ },
+ [],
+ );
+
+ const sortAction = useCallback(
+ (user_id, page_name, table_name, settingValue) => {
+ updateSettingStorage(
+ user_id,
+ page_name,
+ table_name,
+ "sorts",
+ settingValue,
+ );
+ },
+ [],
+ );
+
+ const filterAction = (user_id, page_name, table_name, settingValue) => {
+ updateSettingStorage(
+ user_id,
+ page_name,
+ table_name,
+ "filters",
+ settingValue,
+ );
+ };
+
+ const resetAction = (user_id, page_name, table_name) => {
+ const compressedData = localStorage.getItem("_setting-app");
+ const prevLocalStorage = compressedData
+ ? decompressData(compressedData)
+ : {};
+
+ const userSettings = prevLocalStorage[user_id] || {};
+ const pageSettings = userSettings[page_name] || {};
+ delete pageSettings[table_name];
+
+ const resetData = {
+ ...prevLocalStorage,
+ [user_id]: {
+ ...userSettings,
+ [page_name]: {
+ ...pageSettings,
+ },
+ },
+ };
+
+ localStorage.setItem(
+ "_setting-app",
+ LZString.compressToUTF16(JSON.stringify(resetData)),
+ );
+ setSettingStore(resetData);
+ };
+
+ const updateSettingStorage = (
+ user_id,
+ page_name,
+ table_name,
+ settingType,
+ settingValue,
+ ) => {
+ const compressedData = localStorage.getItem("_setting-app");
+ const prevLocalStorage = compressedData
+ ? decompressData(compressedData)
+ : {};
+
+ const userSettings = prevLocalStorage[user_id] || {};
+ const pageSettings = userSettings[page_name] || {};
+ const tableSettings = pageSettings[table_name] || {};
+
+ let newSettings;
+ if (settingType === "sorts" || settingType === "filters") {
+ newSettings = [...settingValue];
+ } else {
+ newSettings = { ...(tableSettings[settingType] || {}), ...settingValue };
+ }
+
+ const updatedLocalStorage = {
+ ...prevLocalStorage,
+ [user_id]: {
+ ...userSettings,
+ [page_name]: {
+ ...pageSettings,
+ [table_name]: {
+ ...tableSettings,
+ [settingType]: Array.isArray(settingValue)
+ ? [...newSettings]
+ : { ...newSettings },
+ },
+ },
+ },
+ };
+
+ localStorage.setItem(
+ "_setting-app",
+ LZString.compressToUTF16(JSON.stringify(updatedLocalStorage)),
+ );
+ setSettingStore(updatedLocalStorage);
+ };
+
+ const clearAction = (user_id, page_name, table_name, key) => {
+ const compressedData = localStorage.getItem("_setting-app");
+ const prevLocalStorage = compressedData
+ ? decompressData(compressedData)
+ : {};
+
+ const userSettings = prevLocalStorage[user_id] || {};
+ const pageSettings = userSettings[page_name] || {};
+ const tableSettings = pageSettings[table_name] || {};
+
+ const updatedSettings = {
+ ...prevLocalStorage,
+ [user_id]: {
+ ...userSettings,
+ [page_name]: {
+ ...pageSettings,
+ [table_name]: {
+ ...tableSettings,
+ [key]: Array.isArray(tableSettings[key]) ? [] : {},
+ },
+ },
+ },
+ };
+
+ localStorage.setItem(
+ "_setting-app",
+ LZString.compressToUTF16(JSON.stringify(updatedSettings)),
+ );
+ setSettingStore(updatedSettings);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/lib/hooks/useCallerHistory.js b/src/lib/hooks/useCallerHistory.js
new file mode 100644
index 0000000..90857ba
--- /dev/null
+++ b/src/lib/hooks/useCallerHistory.js
@@ -0,0 +1,50 @@
+import { useEffect, useState } from "react";
+import useRequest from "./useRequest";
+import { GET_CALLER_HISTORY } from "@/core/utils/routes";
+
+const useCallerHistory = (callId, phoneNumber, maxSize) => {
+ const requestServer = useRequest();
+
+ const [historyData, setHistoryData] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [hasError, setHasError] = useState(false);
+
+ useEffect(() => {
+ const fetchHistory = async () => {
+ if (!phoneNumber || !maxSize) return;
+
+ setIsLoading(true);
+ setHasError(false);
+
+ try {
+ const url = `${GET_CALLER_HISTORY}?phone_number=${phoneNumber}&size=${maxSize}`;
+ const { data } = await requestServer(url, "get");
+ const items = data?.data || [];
+
+ const filtered = items.filter((item) => item.id !== callId);
+ const unique = Array.from(
+ new Map(filtered.map((item) => [item.id, item])).values(),
+ );
+
+ setHistoryData(unique);
+ } catch (error) {
+ console.error("Error fetching caller history:", error);
+ setHasError(true);
+ setHistoryData([]);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ fetchHistory();
+ }, [callId, phoneNumber, maxSize]);
+
+ return {
+ firstItemOfHistory: historyData[0] || false,
+ historyList: historyData.length > 1 ? historyData.slice(1) : false,
+ isLoadingHistoryList: isLoading,
+ errorHistoryList: hasError,
+ };
+};
+
+export default useCallerHistory;
diff --git a/src/lib/hooks/usePermissions.js b/src/lib/hooks/usePermissions.js
new file mode 100644
index 0000000..b1f2856
--- /dev/null
+++ b/src/lib/hooks/usePermissions.js
@@ -0,0 +1,21 @@
+import { GET_PERMISSIONS_ROUTE } from "@/core/utils/routes";
+import useSWR from "swr";
+import useRequest from "./useRequest";
+
+export const usePermissions = () => {
+ const request = useRequest();
+
+ const fetcher = async (url) => {
+ try {
+ const response = await request(url);
+ return response.data.data;
+ } catch (error) {
+ throw new Error();
+ }
+ };
+
+ return useSWR(GET_PERMISSIONS_ROUTE, fetcher, {
+ keepPreviousData: true,
+ dedupingInterval: 30000,
+ });
+};
diff --git a/src/lib/hooks/useRequest.js b/src/lib/hooks/useRequest.js
new file mode 100644
index 0000000..9f4f2ff
--- /dev/null
+++ b/src/lib/hooks/useRequest.js
@@ -0,0 +1,66 @@
+import { errorResponse } from "@/core/utils/errorResponse";
+import { successRequest } from "@/core/utils/successRequest";
+import axios from "axios";
+import { useAuth } from "../contexts/auth";
+import { useSidebarBadge } from "./useSidebarBadge";
+
+const defaultOptions = {
+ data: {},
+ requestOptions: {
+ headers: {},
+ },
+ notificationShow: true,
+ notificationSuccess: false,
+ notificationFailed: true,
+ hasSidebarUpdate: false,
+};
+
+const useRequest = (initOptions) => {
+ const _options = Object.assign({}, defaultOptions, initOptions);
+
+ const { mutate: sidebarUpdate } = useSidebarBadge({
+ enable: _options.hasSidebarUpdate,
+ });
+ const { logout } = useAuth();
+
+ /**
+ * Performs an HTTP request.
+ * @param {string} url - The URL to send the request to.
+ * @param {'get' | 'post' | 'put' | 'delete'} [method='get'] - HTTP method.
+ * @param {object} [options] - Additional request options.
+ * @returns {Promise} - Axios response.
+ */
+ return async (url = "", method = "get", options) => {
+ const mergedOptions = Object.assign({}, _options, options);
+ try {
+ const response = await axios({
+ url,
+ method,
+ data: method === "get" ? null : mergedOptions.data,
+ withCredentials: true,
+ ...mergedOptions.requestOptions,
+ });
+ if (mergedOptions.hasSidebarUpdate) {
+ if (method === "post" || method === "put" || method === "delete")
+ sidebarUpdate();
+ }
+ successRequest(
+ mergedOptions.notificationShow && mergedOptions.notificationSuccess,
+ "request_data",
+ );
+ return response;
+ } catch (error) {
+ if (error.response) {
+ errorResponse(
+ error.response,
+ mergedOptions.notificationShow && mergedOptions.notificationFailed,
+ "request_data",
+ logout,
+ );
+ }
+ throw error;
+ }
+ };
+};
+
+export default useRequest;
diff --git a/src/lib/hooks/useSidebarBadge.js b/src/lib/hooks/useSidebarBadge.js
new file mode 100644
index 0000000..10e7461
--- /dev/null
+++ b/src/lib/hooks/useSidebarBadge.js
@@ -0,0 +1,23 @@
+import { GET_SIDEBAR_BADGE_ROUTE } from "@/core/utils/routes";
+import axios from "axios";
+import useSWR from "swr";
+
+export const useSidebarBadge = ({ enable = true }) => {
+ const fetcher = async (url) => {
+ try {
+ const response = await axios({
+ url,
+ method: "get",
+ withCredentials: true,
+ });
+ return response.data.data;
+ } catch (error) {
+ throw new Error();
+ }
+ };
+
+ return useSWR(enable ? GET_SIDEBAR_BADGE_ROUTE : "", fetcher, {
+ keepPreviousData: true,
+ dedupingInterval: 30000,
+ });
+};
diff --git a/src/middlewares/AppPermission.jsx b/src/middlewares/AppPermission.jsx
deleted file mode 100644
index 8f93bd3..0000000
--- a/src/middlewares/AppPermission.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-const GLOBAL_HAS_VALUE = process.env.NEXT_PUBLIC_HAS_VALUE;
-const hasPermissionsValue = GLOBAL_HAS_VALUE ? JSON.parse(GLOBAL_HAS_VALUE) : [];
-
-const AppPermission = ({ children , permissions }) => {
- return permissions.some(permission => hasPermissionsValue.includes(permission)) ? <>{children}> : null;
-};
-
-export default AppPermission;
diff --git a/src/middlewares/RolePermission.jsx b/src/middlewares/RolePermission.jsx
deleted file mode 100644
index 4b1cc8a..0000000
--- a/src/middlewares/RolePermission.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import useUser from "@/lib/app/hooks/useUser";
-import RolePermissionComponent from "@/core/components/Middleware/RolePermissionComponent";
-
-const RolePermissionMiddleware = ({children, requiredPermissions}) => {
- const {user} = useUser();
-
- const hasPermission = requiredPermissions.some((permission) =>
- user?.permissions?.includes(permission)
- );
-
- return !hasPermission ? : <>{children}>;
-};
-
-export default RolePermissionMiddleware;
diff --git a/src/middlewares/WithAuth.jsx b/src/middlewares/WithAuth.jsx
deleted file mode 100644
index d3b0493..0000000
--- a/src/middlewares/WithAuth.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import useUser from "@/lib/app/hooks/useUser";
-import WithAuthComponent from "@/core/components/Middleware/WithAuthComponent";
-
-
-const WithAuthMiddleware = ({children}) => {
- const {isAuth} = useUser();
-
- return isAuth ? <>{children}> : ;
-};
-
-export default WithAuthMiddleware;
diff --git a/src/middlewares/WithoutAuth.jsx b/src/middlewares/WithoutAuth.jsx
deleted file mode 100644
index 7fbcba6..0000000
--- a/src/middlewares/WithoutAuth.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import useUser from "@/lib/app/hooks/useUser";
-import {useRouter} from "next/router";
-import {useEffect} from "react";
-import WithoutAuthComponent from "@/core/components/Middleware/WithoutAuthComponent";
-
-const WithoutAuthMiddleware = ({children}) => {
- const {isAuth} = useUser();
- const router = useRouter();
-
- const backUrlDecodedPath = router.query?.back_url;
-
- useEffect(() => {
- if (!isAuth) return;
- const timer = setTimeout(() => {
- router.replace(
- backUrlDecodedPath
- ? decodeURIComponent(backUrlDecodedPath)
- : "/dashboard"
- );
- }, 2000);
-
- return () => {
- clearTimeout(timer);
- };
- }, [isAuth]);
-
- return isAuth ? (
-
- ) : (
- <>{children}>
- );
-};
-
-export default WithoutAuthMiddleware;
diff --git a/src/middlewares/__test__/AppPermission.test.js b/src/middlewares/__test__/AppPermission.test.js
deleted file mode 100644
index 82377ba..0000000
--- a/src/middlewares/__test__/AppPermission.test.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import {render, screen, waitFor} from '@testing-library/react';
-import MockAppWithProviders from "../../../mocks/AppWithProvider";
-import AppPermission from "@/middlewares/AppPermission";
-
-describe('AppPermission From middlewares', () => {
- describe('Behavior', () => {
- it('show related child if permission exist', async () => {
-
- const requiredPermissions = ["NEXT_PUBLIC_HAS_WIDGET"];
- render({'children'});
-
- await waitFor(()=>{
- expect(screen.queryByText('children')).toBeInTheDocument();
- })
- });
- it('do not show related child if permission does not exist', async () => {
-
- const requiredPermissions = ["MISSING_PERMISSION"];
- render();
-
- await waitFor(() => {
- expect(screen.queryByText('children')).not.toBeInTheDocument();
- });
- });
- });
-});
diff --git a/src/middlewares/__test__/RolePermission.test.js b/src/middlewares/__test__/RolePermission.test.js
deleted file mode 100644
index f37796f..0000000
--- a/src/middlewares/__test__/RolePermission.test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import {render, screen, waitFor} from '@testing-library/react';
-import MockAppWithProviders from "../../../mocks/AppWithProvider";
-import RolePermissionMiddleware from "@/middlewares/RolePermission";
-
-
-describe('RolePermissionMiddleware From RolePermissionMiddleware', () => {
- describe('Behavior', () => {
- it('show related child if permission exist', async () => {
-
- const requiredPermissions = ["manage_users"];
- render({'children'});
-
- await waitFor(()=>{
- expect(screen.queryByText('children')).toBeInTheDocument();
-
- })
-
- });
- it('show related error if permission not exist', async () => {
-
- const requiredPermissions = ["other-permission"];
-
- render();
-
- await waitFor(()=>{
-
- expect(screen.queryByText('شما دسترسی لازم برای مشاهده این صفحه را ندارید!')).toBeInTheDocument();
-
- })
-
-
- });
- });
-});
diff --git a/src/pages/403.jsx b/src/pages/403.jsx
deleted file mode 100644
index 15ba915..0000000
--- a/src/pages/403.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import {useEffect, useState} from "react";
-import {useRouter} from "next/router";
-import {NextIntlProvider} from "next-intl";
-import UnAuthorizedComponent from "@/components/errors/403";
-
-export default function Custom404() {
- const router = useRouter()
- const [messages, setMessages] = useState(null)
- useEffect(() => {
- const fetch = async () => {
- const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
- setMessages(tempMessages)
- }
- fetch()
- }, []);
-
- if (!messages) return
-
- return (
-
-
-
- );
-}
diff --git a/src/pages/404.jsx b/src/pages/404.jsx
deleted file mode 100644
index 26de038..0000000
--- a/src/pages/404.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {useEffect, useState} from "react";
-import {useRouter} from "next/router";
-import {NextIntlProvider} from "next-intl";
-import NotFoundComponent from "@/components/errors/404";
-
-export default function Custom404() {
- const router = useRouter()
- const [messages, setMessages] = useState(null)
- useEffect(() => {
-
- const fetch = async () => {
- const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
- setMessages(tempMessages)
- }
- fetch()
- }, []);
-
- if (!messages) return
-
- return (
-
-
-
- );
-}
diff --git a/src/pages/500.jsx b/src/pages/500.jsx
deleted file mode 100644
index 4b85bc2..0000000
--- a/src/pages/500.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import {useEffect, useState} from "react";
-import {useRouter} from "next/router";
-import {NextIntlProvider} from "next-intl";
-import ServerErrorComponent from "@/components/errors/500";
-
-export default function Custom500() {
- const router = useRouter()
- const [messages, setMessages] = useState(null)
- useEffect(() => {
- const fetch = async () => {
- const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
- setMessages(tempMessages)
- }
- fetch()
- }, []);
-
- if (!messages) return
-
- return (
-
-
-
- );
-}
diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx
deleted file mode 100644
index 2d23745..0000000
--- a/src/pages/_app.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import "&/fontiran.css";
-import AppLayout from "@/layouts/AppLayout";
-import MuiLayout from "@/layouts/MuiLayout";
-import {LanguageProvider} from "@/lib/app/contexts/language";
-import {LoadingProvider} from "@/lib/app/contexts/loading";
-import {UserProvider} from "@/lib/app/contexts/user";
-import "moment/locale/fa";
-import {NextIntlProvider} from "next-intl";
-import TitlePage from "@/core/components/TitlePage";
-import {SocketProvider} from "@/lib/app/contexts/socket";
-import {ToastProvider} from "@/lib/app/contexts/toast";
-
-const App = ({Component, pageProps}) => {
-
- return (<>
-
-
-
-
- {pageProps.messages ? : ''}
-
-
-
-
-
-
-
-
-
-
-
-
-
- >)
-};
-
-export default App;
diff --git a/src/pages/_document.jsx b/src/pages/_document.jsx
deleted file mode 100644
index 474e29b..0000000
--- a/src/pages/_document.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import {createEmotionCacheRtl} from "@/core/utils/createEmotionCache";
-import theme from "@/core/utils/theme";
-import createEmotionServer from "@emotion/server/create-instance";
-import Document, {Head, Html, Main, NextScript} from "next/document";
-
-export default function MyDocument(props) {
- const {emotionStyleTags} = props;
-
- return (
-
-
-
-
-
-
- {emotionStyleTags}
-
-
-
-
-
-
- );
-}
-
-MyDocument.getInitialProps = async (ctx) => {
- const originalRenderPage = ctx.renderPage;
- let cache;
- switch (ctx.locale) {
- case "fa":
- cache = createEmotionCacheRtl();
- break;
- }
-
- const {extractCriticalToChunks} = createEmotionServer(cache);
-
- ctx.renderPage = () =>
- originalRenderPage({
- enhanceApp: (App) =>
- function EnhanceApp(props) {
- return ;
- },
- });
-
- const initialProps = await Document.getInitialProps(ctx);
-
- const emotionStyles = extractCriticalToChunks(initialProps.html);
- const emotionStyleTags = emotionStyles.styles.map((style) => (
-
- ));
-
- return {
- ...initialProps,
- emotionStyleTags,
- };
-};
diff --git a/src/pages/dashboard/change-password/index.jsx b/src/pages/dashboard/change-password/index.jsx
deleted file mode 100644
index f744382..0000000
--- a/src/pages/dashboard/change-password/index.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import DashboardChangePasswordComponent from "@/components/dashboard/change-password";
-import WithAuthMiddleware from "@/middlewares/WithAuth";
-import {parse} from "next-useragent";
-
-export default function LoanFollowUp() {
- return (
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Dashboard.change_password",
- isBot,
- locale
- },
- };
-}
diff --git a/src/pages/dashboard/edit-profile/index.jsx b/src/pages/dashboard/edit-profile/index.jsx
deleted file mode 100644
index dfa2eec..0000000
--- a/src/pages/dashboard/edit-profile/index.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import DashboardEditProfile from "@/components/dashboard/edit-profile";
-import WithAuthMiddleware from "@/middlewares/WithAuth";
-import {parse} from "next-useragent";
-
-export default function LoanFollowUp() {
- return (
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Dashboard.edit_profile",
- isBot,
- locale
- },
- };
-}
diff --git a/src/pages/dashboard/expert-management/index.jsx b/src/pages/dashboard/expert-management/index.jsx
deleted file mode 100644
index 60dc6e2..0000000
--- a/src/pages/dashboard/expert-management/index.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import WithAuthMiddleware from "@/middlewares/WithAuth";
-import {parse} from "next-useragent";
-import DashboardExpertManagementComponent from "@/components/dashboard/expert-management";
-
-export default function ExpertManagement() {
- return (
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Dashboard.expert_management",
- isBot,
- locale
- },
- };
-}
diff --git a/src/pages/dashboard/index.jsx b/src/pages/dashboard/index.jsx
deleted file mode 100644
index eed56eb..0000000
--- a/src/pages/dashboard/index.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import DashboardFirstComponent from "@/components/dashboard/first";
-import WithAuthMiddleware from "@/middlewares/WithAuth";
-import {parse} from "next-useragent";
-
-export default function Dashboard() {
- return (
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Dashboard.dashboard_page",
- isBot,
- locale
- },
- };
-}
diff --git a/src/pages/dashboard/role-management/index.jsx b/src/pages/dashboard/role-management/index.jsx
deleted file mode 100644
index c309729..0000000
--- a/src/pages/dashboard/role-management/index.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import RolePermissionMiddleware from "@/middlewares/RolePermission";
-import WithAuthMiddleware from "@/middlewares/WithAuth";
-import {parse} from "next-useragent";
-import DashboardRoleManagementComponent from "@/components/dashboard/role-management";
-
-const requiredPermissions = ["manage_roles"];
-export default function RoleManagement() {
- return (
-
-
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Dashboard.role_management_page",
- isBot,
- },
- };
-}
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
deleted file mode 100644
index 996ba03..0000000
--- a/src/pages/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import FirstComponent from "@/components/first";
-import {parse} from "next-useragent";
-
-export default function Home() {
- return (
- <>
-
- >
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "first_page",
- isBot,
- locale
- },
- };
-}
diff --git a/src/pages/login-expert.jsx b/src/pages/login-expert.jsx
deleted file mode 100644
index 393f916..0000000
--- a/src/pages/login-expert.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import LoginComponent from "@/components/login-expert";
-import WithoutAuthMiddleware from "@/middlewares/WithoutAuth";
-import {parse} from "next-useragent";
-
-export default function Login() {
- return (
-
-
-
- );
-}
-
-export async function getServerSideProps({req, locale}) {
- const {isBot} = parse(req.headers["user-agent"]);
- return {
- props: {
- messages: (await import(`&/locales/${locale}/app.json`)).default,
- title: "Titles.title_login_expert_page",
- isBot,
- locale
- },
- };
-}